1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

Upgrade openssl from 1.1.0e to 1.1.1b, with source code. 4.0.78

This commit is contained in:
winlin 2021-03-01 20:47:57 +08:00
parent 8f1c992379
commit 96dbd7bced
1476 changed files with 616554 additions and 4 deletions

View file

@ -0,0 +1,211 @@
Notes: 2001-09-24
-----------------
This "description" (if one chooses to call it that) needed some major updating
so here goes. This update addresses a change being made at the same time to
OpenSSL, and it pretty much completely restructures the underlying mechanics of
the "ENGINE" code. So it serves a double purpose of being a "ENGINE internals
for masochists" document *and* a rather extensive commit log message. (I'd get
lynched for sticking all this in CHANGES or the commit mails :-).
ENGINE_TABLE underlies this restructuring, as described in the internal header
"eng_int.h", implemented in eng_table.c, and used in each of the "class" files;
tb_rsa.c, tb_dsa.c, etc.
However, "EVP_CIPHER" underlies the motivation and design of ENGINE_TABLE so
I'll mention a bit about that first. EVP_CIPHER (and most of this applies
equally to EVP_MD for digests) is both a "method" and a algorithm/mode
identifier that, in the current API, "lingers". These cipher description +
implementation structures can be defined or obtained directly by applications,
or can be loaded "en masse" into EVP storage so that they can be catalogued and
searched in various ways, ie. two ways of encrypting with the "des_cbc"
algorithm/mode pair are;
(i) directly;
const EVP_CIPHER *cipher = EVP_des_cbc();
EVP_EncryptInit(&ctx, cipher, key, iv);
[ ... use EVP_EncryptUpdate() and EVP_EncryptFinal() ...]
(ii) indirectly;
OpenSSL_add_all_ciphers();
cipher = EVP_get_cipherbyname("des_cbc");
EVP_EncryptInit(&ctx, cipher, key, iv);
[ ... etc ... ]
The latter is more generally used because it also allows ciphers/digests to be
looked up based on other identifiers which can be useful for automatic cipher
selection, eg. in SSL/TLS, or by user-controllable configuration.
The important point about this is that EVP_CIPHER definitions and structures are
passed around with impunity and there is no safe way, without requiring massive
rewrites of many applications, to assume that EVP_CIPHERs can be reference
counted. One an EVP_CIPHER is exposed to the caller, neither it nor anything it
comes from can "safely" be destroyed. Unless of course the way of getting to
such ciphers is via entirely distinct API calls that didn't exist before.
However existing API usage cannot be made to understand when an EVP_CIPHER
pointer, that has been passed to the caller, is no longer being used.
The other problem with the existing API w.r.t. to hooking EVP_CIPHER support
into ENGINE is storage - the OBJ_NAME-based storage used by EVP to register
ciphers simultaneously registers cipher *types* and cipher *implementations* -
they are effectively the same thing, an "EVP_CIPHER" pointer. The problem with
hooking in ENGINEs is that multiple ENGINEs may implement the same ciphers. The
solution is necessarily that ENGINE-provided ciphers simply are not registered,
stored, or exposed to the caller in the same manner as existing ciphers. This is
especially necessary considering the fact ENGINE uses reference counts to allow
for cleanup, modularity, and DSO support - yet EVP_CIPHERs, as exposed to
callers in the current API, support no such controls.
Another sticking point for integrating cipher support into ENGINE is linkage.
Already there is a problem with the way ENGINE supports RSA, DSA, etc whereby
they are available *because* they're part of a giant ENGINE called "openssl".
Ie. all implementations *have* to come from an ENGINE, but we get round that by
having a giant ENGINE with all the software support encapsulated. This creates
linker hassles if nothing else - linking a 1-line application that calls 2 basic
RSA functions (eg. "RSA_free(RSA_new());") will result in large quantities of
ENGINE code being linked in *and* because of that DSA, DH, and RAND also. If we
continue with this approach for EVP_CIPHER support (even if it *was* possible)
we would lose our ability to link selectively by selectively loading certain
implementations of certain functionality. Touching any part of any kind of
crypto would result in massive static linkage of everything else. So the
solution is to change the way ENGINE feeds existing "classes", ie. how the
hooking to ENGINE works from RSA, DSA, DH, RAND, as well as adding new hooking
for EVP_CIPHER, and EVP_MD.
The way this is now being done is by mostly reverting back to how things used to
work prior to ENGINE :-). Ie. RSA now has a "RSA_METHOD" pointer again - this
was previously replaced by an "ENGINE" pointer and all RSA code that required
the RSA_METHOD would call ENGINE_get_RSA() each time on its ENGINE handle to
temporarily get and use the ENGINE's RSA implementation. Apart from being more
efficient, switching back to each RSA having an RSA_METHOD pointer also allows
us to conceivably operate with *no* ENGINE. As we'll see, this removes any need
for a fallback ENGINE that encapsulates default implementations - we can simply
have our RSA structure pointing its RSA_METHOD pointer to the software
implementation and have its ENGINE pointer set to NULL.
A look at the EVP_CIPHER hooking is most explanatory, the RSA, DSA (etc) cases
turn out to be degenerate forms of the same thing. The EVP storage of ciphers,
and the existing EVP API functions that return "software" implementations and
descriptions remain untouched. However, the storage takes more meaning in terms
of "cipher description" and less meaning in terms of "implementation". When an
EVP_CIPHER_CTX is actually initialised with an EVP_CIPHER method and is about to
begin en/decryption, the hooking to ENGINE comes into play. What happens is that
cipher-specific ENGINE code is asked for an ENGINE pointer (a functional
reference) for any ENGINE that is registered to perform the algo/mode that the
provided EVP_CIPHER structure represents. Under normal circumstances, that
ENGINE code will return NULL because no ENGINEs will have had any cipher
implementations *registered*. As such, a NULL ENGINE pointer is stored in the
EVP_CIPHER_CTX context, and the EVP_CIPHER structure is left hooked into the
context and so is used as the implementation. Pretty much how things work now
except we'd have a redundant ENGINE pointer set to NULL and doing nothing.
Conversely, if an ENGINE *has* been registered to perform the algorithm/mode
combination represented by the provided EVP_CIPHER, then a functional reference
to that ENGINE will be returned to the EVP_CIPHER_CTX during initialisation.
That functional reference will be stored in the context (and released on
cleanup) - and having that reference provides a *safe* way to use an EVP_CIPHER
definition that is private to the ENGINE. Ie. the EVP_CIPHER provided by the
application will actually be replaced by an EVP_CIPHER from the registered
ENGINE - it will support the same algorithm/mode as the original but will be a
completely different implementation. Because this EVP_CIPHER isn't stored in the
EVP storage, nor is it returned to applications from traditional API functions,
there is no associated problem with it not having reference counts. And of
course, when one of these "private" cipher implementations is hooked into
EVP_CIPHER_CTX, it is done whilst the EVP_CIPHER_CTX holds a functional
reference to the ENGINE that owns it, thus the use of the ENGINE's EVP_CIPHER is
safe.
The "cipher-specific ENGINE code" I mentioned is implemented in tb_cipher.c but
in essence it is simply an instantiation of "ENGINE_TABLE" code for use by
EVP_CIPHER code. tb_digest.c is virtually identical but, of course, it is for
use by EVP_MD code. Ditto for tb_rsa.c, tb_dsa.c, etc. These instantiations of
ENGINE_TABLE essentially provide linker-separation of the classes so that even
if ENGINEs implement *all* possible algorithms, an application using only
EVP_CIPHER code will link at most code relating to EVP_CIPHER, tb_cipher.c, core
ENGINE code that is independent of class, and of course the ENGINE
implementation that the application loaded. It will *not* however link any
class-specific ENGINE code for digests, RSA, etc nor will it bleed over into
other APIs, such as the RSA/DSA/etc library code.
ENGINE_TABLE is a little more complicated than may seem necessary but this is
mostly to avoid a lot of "init()"-thrashing on ENGINEs (that may have to load
DSOs, and other expensive setup that shouldn't be thrashed unnecessarily) *and*
to duplicate "default" behaviour. Basically an ENGINE_TABLE instantiation, for
example tb_cipher.c, implements a hash-table keyed by integer "nid" values.
These nids provide the uniquenness of an algorithm/mode - and each nid will hash
to a potentially NULL "ENGINE_PILE". An ENGINE_PILE is essentially a list of
pointers to ENGINEs that implement that particular 'nid'. Each "pile" uses some
caching tricks such that requests on that 'nid' will be cached and all future
requests will return immediately (well, at least with minimal operation) unless
a change is made to the pile, eg. perhaps an ENGINE was unloaded. The reason is
that an application could have support for 10 ENGINEs statically linked
in, and the machine in question may not have any of the hardware those 10
ENGINEs support. If each of those ENGINEs has a "des_cbc" implementation, we
want to avoid every EVP_CIPHER_CTX setup from trying (and failing) to initialise
each of those 10 ENGINEs. Instead, the first such request will try to do that
and will either return (and cache) a NULL ENGINE pointer or will return a
functional reference to the first that successfully initialised. In the latter
case it will also cache an extra functional reference to the ENGINE as a
"default" for that 'nid'. The caching is acknowledged by a 'uptodate' variable
that is unset only if un/registration takes place on that pile. Ie. if
implementations of "des_cbc" are added or removed. This behaviour can be
tweaked; the ENGINE_TABLE_FLAG_NOINIT value can be passed to
ENGINE_set_table_flags(), in which case the only ENGINEs that tb_cipher.c will
try to initialise from the "pile" will be those that are already initialised
(ie. it's simply an increment of the functional reference count, and no real
"initialisation" will take place).
RSA, DSA, DH, and RAND all have their own ENGINE_TABLE code as well, and the
difference is that they all use an implicit 'nid' of 1. Whereas EVP_CIPHERs are
actually qualitatively different depending on 'nid' (the "des_cbc" EVP_CIPHER is
not an interoperable implementation of "aes_256_cbc"), RSA_METHODs are
necessarily interoperable and don't have different flavours, only different
implementations. In other words, the ENGINE_TABLE for RSA will either be empty,
or will have a single ENGINE_PILE hashed to by the 'nid' 1 and that pile
represents ENGINEs that implement the single "type" of RSA there is.
Cleanup - the registration and unregistration may pose questions about how
cleanup works with the ENGINE_PILE doing all this caching nonsense (ie. when the
application or EVP_CIPHER code releases its last reference to an ENGINE, the
ENGINE_PILE code may still have references and thus those ENGINEs will stay
hooked in forever). The way this is handled is via "unregistration". With these
new ENGINE changes, an abstract ENGINE can be loaded and initialised, but that
is an algorithm-agnostic process. Even if initialised, it will not have
registered any of its implementations (to do so would link all class "table"
code despite the fact the application may use only ciphers, for example). This
is deliberately a distinct step. Moreover, registration and unregistration has
nothing to do with whether an ENGINE is *functional* or not (ie. you can even
register an ENGINE and its implementations without it being operational, you may
not even have the drivers to make it operate). What actually happens with
respect to cleanup is managed inside eng_lib.c with the "engine_cleanup_***"
functions. These functions are internal-only and each part of ENGINE code that
could require cleanup will, upon performing its first allocation, register a
callback with the "engine_cleanup" code. The other part of this that makes it
tick is that the ENGINE_TABLE instantiations (tb_***.c) use NULL as their
initialised state. So if RSA code asks for an ENGINE and no ENGINE has
registered an implementation, the code will simply return NULL and the tb_rsa.c
state will be unchanged. Thus, no cleanup is required unless registration takes
place. ENGINE_cleanup() will simply iterate across a list of registered cleanup
callbacks calling each in turn, and will then internally delete its own storage
(a STACK). When a cleanup callback is next registered (eg. if the cleanup() is
part of a graceful restart and the application wants to cleanup all state then
start again), the internal STACK storage will be freshly allocated. This is much
the same as the situation in the ENGINE_TABLE instantiations ... NULL is the
initialised state, so only modification operations (not queries) will cause that
code to have to register a cleanup.
What else? The bignum callbacks and associated ENGINE functions have been
removed for two obvious reasons; (i) there was no way to generalise them to the
mechanism now used by RSA/DSA/..., because there's no such thing as a BIGNUM
method, and (ii) because of (i), there was no meaningful way for library or
application code to automatically hook and use ENGINE supplied bignum functions
anyway. Also, ENGINE_cpy() has been removed (although an internal-only version
exists) - the idea of providing an ENGINE_cpy() function probably wasn't a good
one and now certainly doesn't make sense in any generalised way. Some of the
RSA, DSA, DH, and RAND functions that were fiddled during the original ENGINE
changes have now, as a consequence, been reverted back. This is because the
hooking of ENGINE is now automatic (and passive, it can internally use a NULL
ENGINE pointer to simply ignore ENGINE from then on).
Hell, that should be enough for now ... comments welcome.

View file

@ -0,0 +1,11 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
eng_err.c eng_lib.c eng_list.c eng_init.c eng_ctrl.c \
eng_table.c eng_pkey.c eng_fat.c eng_all.c \
tb_rsa.c tb_dsa.c tb_dh.c tb_rand.c \
tb_cipher.c tb_digest.c tb_pkmeth.c tb_asnmth.c tb_eckey.c \
eng_openssl.c eng_cnf.c eng_dyn.c \
eng_rdrand.c
IF[{- !$disabled{devcryptoeng} -}]
SOURCE[../../libcrypto]=eng_devcrypto.c
ENDIF

View file

@ -0,0 +1,25 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "internal/cryptlib.h"
#include "eng_int.h"
void ENGINE_load_builtin_engines(void)
{
/* Some ENGINEs need this */
OPENSSL_cpuid_setup();
OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL);
}
#if (defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)) && OPENSSL_API_COMPAT < 0x10100000L
void ENGINE_setup_bsd_cryptodev(void)
{
}
#endif

View file

@ -0,0 +1,192 @@
/*
* Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
#include <openssl/conf.h>
/* #define ENGINE_CONF_DEBUG */
/* ENGINE config module */
static const char *skip_dot(const char *name)
{
const char *p = strchr(name, '.');
if (p != NULL)
return p + 1;
return name;
}
static STACK_OF(ENGINE) *initialized_engines = NULL;
static int int_engine_init(ENGINE *e)
{
if (!ENGINE_init(e))
return 0;
if (!initialized_engines)
initialized_engines = sk_ENGINE_new_null();
if (!initialized_engines || !sk_ENGINE_push(initialized_engines, e)) {
ENGINE_finish(e);
return 0;
}
return 1;
}
static int int_engine_configure(const char *name, const char *value, const CONF *cnf)
{
int i;
int ret = 0;
long do_init = -1;
STACK_OF(CONF_VALUE) *ecmds;
CONF_VALUE *ecmd = NULL;
const char *ctrlname, *ctrlvalue;
ENGINE *e = NULL;
int soft = 0;
name = skip_dot(name);
#ifdef ENGINE_CONF_DEBUG
fprintf(stderr, "Configuring engine %s\n", name);
#endif
/* Value is a section containing ENGINE commands */
ecmds = NCONF_get_section(cnf, value);
if (!ecmds) {
ENGINEerr(ENGINE_F_INT_ENGINE_CONFIGURE,
ENGINE_R_ENGINE_SECTION_ERROR);
return 0;
}
for (i = 0; i < sk_CONF_VALUE_num(ecmds); i++) {
ecmd = sk_CONF_VALUE_value(ecmds, i);
ctrlname = skip_dot(ecmd->name);
ctrlvalue = ecmd->value;
#ifdef ENGINE_CONF_DEBUG
fprintf(stderr, "ENGINE conf: doing ctrl(%s,%s)\n", ctrlname,
ctrlvalue);
#endif
/* First handle some special pseudo ctrls */
/* Override engine name to use */
if (strcmp(ctrlname, "engine_id") == 0)
name = ctrlvalue;
else if (strcmp(ctrlname, "soft_load") == 0)
soft = 1;
/* Load a dynamic ENGINE */
else if (strcmp(ctrlname, "dynamic_path") == 0) {
e = ENGINE_by_id("dynamic");
if (!e)
goto err;
if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", ctrlvalue, 0))
goto err;
if (!ENGINE_ctrl_cmd_string(e, "LIST_ADD", "2", 0))
goto err;
if (!ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0))
goto err;
}
/* ... add other pseudos here ... */
else {
/*
* At this point we need an ENGINE structural reference if we
* don't already have one.
*/
if (!e) {
e = ENGINE_by_id(name);
if (!e && soft) {
ERR_clear_error();
return 1;
}
if (!e)
goto err;
}
/*
* Allow "EMPTY" to mean no value: this allows a valid "value" to
* be passed to ctrls of type NO_INPUT
*/
if (strcmp(ctrlvalue, "EMPTY") == 0)
ctrlvalue = NULL;
if (strcmp(ctrlname, "init") == 0) {
if (!NCONF_get_number_e(cnf, value, "init", &do_init))
goto err;
if (do_init == 1) {
if (!int_engine_init(e))
goto err;
} else if (do_init != 0) {
ENGINEerr(ENGINE_F_INT_ENGINE_CONFIGURE,
ENGINE_R_INVALID_INIT_VALUE);
goto err;
}
} else if (strcmp(ctrlname, "default_algorithms") == 0) {
if (!ENGINE_set_default_string(e, ctrlvalue))
goto err;
} else if (!ENGINE_ctrl_cmd_string(e, ctrlname, ctrlvalue, 0))
goto err;
}
}
if (e && (do_init == -1) && !int_engine_init(e)) {
ecmd = NULL;
goto err;
}
ret = 1;
err:
if (ret != 1) {
ENGINEerr(ENGINE_F_INT_ENGINE_CONFIGURE,
ENGINE_R_ENGINE_CONFIGURATION_ERROR);
if (ecmd)
ERR_add_error_data(6, "section=", ecmd->section,
", name=", ecmd->name,
", value=", ecmd->value);
}
ENGINE_free(e);
return ret;
}
static int int_engine_module_init(CONF_IMODULE *md, const CONF *cnf)
{
STACK_OF(CONF_VALUE) *elist;
CONF_VALUE *cval;
int i;
#ifdef ENGINE_CONF_DEBUG
fprintf(stderr, "Called engine module: name %s, value %s\n",
CONF_imodule_get_name(md), CONF_imodule_get_value(md));
#endif
/* Value is a section containing ENGINEs to configure */
elist = NCONF_get_section(cnf, CONF_imodule_get_value(md));
if (!elist) {
ENGINEerr(ENGINE_F_INT_ENGINE_MODULE_INIT,
ENGINE_R_ENGINES_SECTION_ERROR);
return 0;
}
for (i = 0; i < sk_CONF_VALUE_num(elist); i++) {
cval = sk_CONF_VALUE_value(elist, i);
if (!int_engine_configure(cval->name, cval->value, cnf))
return 0;
}
return 1;
}
static void int_engine_module_finish(CONF_IMODULE *md)
{
ENGINE *e;
while ((e = sk_ENGINE_pop(initialized_engines)))
ENGINE_finish(e);
sk_ENGINE_free(initialized_engines);
initialized_engines = NULL;
}
void ENGINE_add_conf_module(void)
{
CONF_module_add("engines",
int_engine_module_init, int_engine_module_finish);
}

View file

@ -0,0 +1,330 @@
/*
* Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
/*
* When querying a ENGINE-specific control command's 'description', this
* string is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL.
*/
static const char *int_no_description = "";
/*
* These internal functions handle 'CMD'-related control commands when the
* ENGINE in question has asked us to take care of it (ie. the ENGINE did not
* set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag.
*/
static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
{
if ((defn->cmd_num == 0) || (defn->cmd_name == NULL))
return 1;
return 0;
}
static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
{
int idx = 0;
while (!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0)) {
idx++;
defn++;
}
if (int_ctrl_cmd_is_null(defn))
/* The given name wasn't found */
return -1;
return idx;
}
static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
{
int idx = 0;
/*
* NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
* our searches don't need to take any longer than necessary.
*/
while (!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num)) {
idx++;
defn++;
}
if (defn->cmd_num == num)
return idx;
/* The given cmd_num wasn't found */
return -1;
}
static int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p,
void (*f) (void))
{
int idx;
char *s = (char *)p;
const ENGINE_CMD_DEFN *cdp;
/* Take care of the easy one first (eg. it requires no searches) */
if (cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE) {
if ((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
return 0;
return e->cmd_defns->cmd_num;
}
/* One or two commands require that "p" be a valid string buffer */
if ((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) ||
(cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
(cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) {
if (s == NULL) {
ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ERR_R_PASSED_NULL_PARAMETER);
return -1;
}
}
/* Now handle cmd_name -> cmd_num conversion */
if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) {
if ((e->cmd_defns == NULL)
|| ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) {
ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INVALID_CMD_NAME);
return -1;
}
return e->cmd_defns[idx].cmd_num;
}
/*
* For the rest of the commands, the 'long' argument must specify a valid
* command number - so we need to conduct a search.
*/
if ((e->cmd_defns == NULL)
|| ((idx = int_ctrl_cmd_by_num(e->cmd_defns, (unsigned int)i)) < 0)) {
ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INVALID_CMD_NUMBER);
return -1;
}
/* Now the logic splits depending on command type */
cdp = &e->cmd_defns[idx];
switch (cmd) {
case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
cdp++;
return int_ctrl_cmd_is_null(cdp) ? 0 : cdp->cmd_num;
case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
return strlen(cdp->cmd_name);
case ENGINE_CTRL_GET_NAME_FROM_CMD:
return strlen(strcpy(s, cdp->cmd_name));
case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
return strlen(cdp->cmd_desc == NULL ? int_no_description
: cdp->cmd_desc);
case ENGINE_CTRL_GET_DESC_FROM_CMD:
return strlen(strcpy(s, cdp->cmd_desc == NULL ? int_no_description
: cdp->cmd_desc));
case ENGINE_CTRL_GET_CMD_FLAGS:
return cdp->cmd_flags;
}
/* Shouldn't really be here ... */
ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INTERNAL_LIST_ERROR);
return -1;
}
int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
{
int ctrl_exists, ref_exists;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_CTRL, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
ref_exists = ((e->struct_ref > 0) ? 1 : 0);
CRYPTO_THREAD_unlock(global_engine_lock);
ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
if (!ref_exists) {
ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_REFERENCE);
return 0;
}
/*
* Intercept any "root-level" commands before trying to hand them on to
* ctrl() handlers.
*/
switch (cmd) {
case ENGINE_CTRL_HAS_CTRL_FUNCTION:
return ctrl_exists;
case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
case ENGINE_CTRL_GET_CMD_FROM_NAME:
case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
case ENGINE_CTRL_GET_NAME_FROM_CMD:
case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
case ENGINE_CTRL_GET_DESC_FROM_CMD:
case ENGINE_CTRL_GET_CMD_FLAGS:
if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
return int_ctrl_helper(e, cmd, i, p, f);
if (!ctrl_exists) {
ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_CONTROL_FUNCTION);
/*
* For these cmd-related functions, failure is indicated by a -1
* return value (because 0 is used as a valid return in some
* places).
*/
return -1;
}
default:
break;
}
/* Anything else requires a ctrl() handler to exist. */
if (!ctrl_exists) {
ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_CONTROL_FUNCTION);
return 0;
}
return e->ctrl(e, cmd, i, p, f);
}
int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
{
int flags;
if ((flags =
ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0) {
ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,
ENGINE_R_INVALID_CMD_NUMBER);
return 0;
}
if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
!(flags & ENGINE_CMD_FLAG_NUMERIC) &&
!(flags & ENGINE_CMD_FLAG_STRING))
return 0;
return 1;
}
int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
long i, void *p, void (*f) (void), int cmd_optional)
{
int num;
if (e == NULL || cmd_name == NULL) {
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (e->ctrl == NULL
|| (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
0, (void *)cmd_name, NULL)) <= 0) {
/*
* If the command didn't *have* to be supported, we fake success.
* This allows certain settings to be specified for multiple ENGINEs
* and only require a change of ENGINE id (without having to
* selectively apply settings). Eg. changing from a hardware device
* back to the regular software ENGINE without editing the config
* file, etc.
*/
if (cmd_optional) {
ERR_clear_error();
return 1;
}
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, ENGINE_R_INVALID_CMD_NAME);
return 0;
}
/*
* Force the result of the control command to 0 or 1, for the reasons
* mentioned before.
*/
if (ENGINE_ctrl(e, num, i, p, f) > 0)
return 1;
return 0;
}
int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
int cmd_optional)
{
int num, flags;
long l;
char *ptr;
if (e == NULL || cmd_name == NULL) {
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (e->ctrl == NULL
|| (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
0, (void *)cmd_name, NULL)) <= 0) {
/*
* If the command didn't *have* to be supported, we fake success.
* This allows certain settings to be specified for multiple ENGINEs
* and only require a change of ENGINE id (without having to
* selectively apply settings). Eg. changing from a hardware device
* back to the regular software ENGINE without editing the config
* file, etc.
*/
if (cmd_optional) {
ERR_clear_error();
return 1;
}
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, ENGINE_R_INVALID_CMD_NAME);
return 0;
}
if (!ENGINE_cmd_is_executable(e, num)) {
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
ENGINE_R_CMD_NOT_EXECUTABLE);
return 0;
}
flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL);
if (flags < 0) {
/*
* Shouldn't happen, given that ENGINE_cmd_is_executable() returned
* success.
*/
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
ENGINE_R_INTERNAL_LIST_ERROR);
return 0;
}
/*
* If the command takes no input, there must be no input. And vice versa.
*/
if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
if (arg != NULL) {
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
ENGINE_R_COMMAND_TAKES_NO_INPUT);
return 0;
}
/*
* We deliberately force the result of ENGINE_ctrl() to 0 or 1 rather
* than returning it as "return data". This is to ensure usage of
* these commands is consistent across applications and that certain
* applications don't understand it one way, and others another.
*/
if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
return 1;
return 0;
}
/* So, we require input */
if (arg == NULL) {
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
ENGINE_R_COMMAND_TAKES_INPUT);
return 0;
}
/* If it takes string input, that's easy */
if (flags & ENGINE_CMD_FLAG_STRING) {
/* Same explanation as above */
if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
return 1;
return 0;
}
/*
* If it doesn't take numeric either, then it is unsupported for use in a
* config-setting situation, which is what this function is for. This
* should never happen though, because ENGINE_cmd_is_executable() was
* used.
*/
if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) {
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
ENGINE_R_INTERNAL_LIST_ERROR);
return 0;
}
l = strtol(arg, &ptr, 10);
if ((arg == ptr) || (*ptr != '\0')) {
ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
return 0;
}
/*
* Force the result of the control command to 0 or 1, for the reasons
* mentioned before.
*/
if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0)
return 1;
return 0;
}

View file

@ -0,0 +1,836 @@
/*
* Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "e_os.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <assert.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/objects.h>
#include <crypto/cryptodev.h>
#include "internal/engine.h"
/* #define ENGINE_DEVCRYPTO_DEBUG */
#ifdef CRYPTO_ALGORITHM_MIN
# define CHECK_BSD_STYLE_MACROS
#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?
*/
static int cfd;
static int clean_devcrypto_session(struct session_op *sess) {
if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {
SYSerr(SYS_F_IOCTL, errno);
return 0;
}
memset(sess, 0, sizeof(struct session_op));
return 1;
}
/******************************************************************************
*
* Ciphers
*
* Because they all do the same basic operation, we have only one set of
* method functions for them all to share, and a mapping table between
* NIDs and cryptodev IDs, with all the necessary size data.
*
*****/
struct cipher_ctx {
struct session_op sess;
int op; /* COP_ENCRYPT or COP_DECRYPT */
unsigned long mode; /* EVP_CIPH_*_MODE */
/* to handle ctr mode being a stream cipher */
unsigned char partial[EVP_MAX_BLOCK_LENGTH];
unsigned int blocksize, num;
};
static const struct cipher_data_st {
int nid;
int blocksize;
int keylen;
int ivlen;
int flags;
int devcryptoid;
} cipher_data[] = {
#ifndef OPENSSL_NO_DES
{ NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC },
{ NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC },
#endif
#ifndef OPENSSL_NO_BF
{ NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC },
#endif
#ifndef OPENSSL_NO_CAST
{ NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC },
#endif
{ NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
{ NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
{ NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
#ifndef OPENSSL_NO_RC4
{ NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4 },
#endif
#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_CTR)
{ NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
{ NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
{ NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
#endif
#if 0 /* Not yet supported */
{ NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
{ NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
#endif
#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB)
{ NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
{ NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
{ NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
#endif
#if 0 /* Not yet supported */
{ NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
{ NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
{ NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
#endif
#ifndef OPENSSL_NO_CAMELLIA
{ NID_camellia_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE,
CRYPTO_CAMELLIA_CBC },
{ NID_camellia_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE,
CRYPTO_CAMELLIA_CBC },
{ NID_camellia_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE,
CRYPTO_CAMELLIA_CBC },
#endif
};
static size_t get_cipher_data_index(int nid)
{
size_t i;
for (i = 0; i < OSSL_NELEM(cipher_data); i++)
if (nid == cipher_data[i].nid)
return i;
/*
* Code further down must make sure that only NIDs in the table above
* are used. If any other NID reaches this function, there's a grave
* coding error further down.
*/
assert("Code that never should be reached" == NULL);
return -1;
}
static const struct cipher_data_st *get_cipher_data(int nid)
{
return &cipher_data[get_cipher_data_index(nid)];
}
/*
* Following are the three necessary functions to map OpenSSL functionality
* with cryptodev.
*/
static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
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));
/* cleanup a previous session */
if (cipher_ctx->sess.ses != 0 &&
clean_devcrypto_session(&cipher_ctx->sess) == 0)
return 0;
cipher_ctx->sess.cipher = cipher_d->devcryptoid;
cipher_ctx->sess.keylen = cipher_d->keylen;
cipher_ctx->sess.key = (void *)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) {
SYSerr(SYS_F_IOCTL, errno);
return 0;
}
return 1;
}
static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
struct cipher_ctx *cipher_ctx =
(struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
struct crypt_op cryp;
unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
#if !defined(COP_FLAG_WRITE_IV)
unsigned char saved_iv[EVP_MAX_IV_LENGTH];
const unsigned char *ivptr;
size_t nblocks, ivlen;
#endif
memset(&cryp, 0, sizeof(cryp));
cryp.ses = cipher_ctx->sess.ses;
cryp.len = inl;
cryp.src = (void *)in;
cryp.dst = (void *)out;
cryp.iv = (void *)iv;
cryp.op = cipher_ctx->op;
#if !defined(COP_FLAG_WRITE_IV)
cryp.flags = 0;
ivlen = EVP_CIPHER_CTX_iv_length(ctx);
if (ivlen > 0)
switch (cipher_ctx->mode) {
case EVP_CIPH_CBC_MODE:
assert(inl >= ivlen);
if (!EVP_CIPHER_CTX_encrypting(ctx)) {
ivptr = in + inl - ivlen;
memcpy(saved_iv, ivptr, ivlen);
}
break;
case EVP_CIPH_CTR_MODE:
break;
default: /* should not happen */
return 0;
}
#else
cryp.flags = COP_FLAG_WRITE_IV;
#endif
if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) {
SYSerr(SYS_F_IOCTL, errno);
return 0;
}
#if !defined(COP_FLAG_WRITE_IV)
if (ivlen > 0)
switch (cipher_ctx->mode) {
case EVP_CIPH_CBC_MODE:
assert(inl >= ivlen);
if (EVP_CIPHER_CTX_encrypting(ctx))
ivptr = out + inl - ivlen;
else
ivptr = saved_iv;
memcpy(iv, ivptr, ivlen);
break;
case EVP_CIPH_CTR_MODE:
nblocks = (inl + cipher_ctx->blocksize - 1)
/ cipher_ctx->blocksize;
do {
ivlen--;
nblocks += iv[ivlen];
iv[ivlen] = (uint8_t) nblocks;
nblocks >>= 8;
} while (ivlen);
break;
default: /* should not happen */
return 0;
}
#endif
return 1;
}
static int ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
struct cipher_ctx *cipher_ctx =
(struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
size_t nblocks, len;
/* initial partial block */
while (cipher_ctx->num && inl) {
(*out++) = *(in++) ^ cipher_ctx->partial[cipher_ctx->num];
--inl;
cipher_ctx->num = (cipher_ctx->num + 1) % cipher_ctx->blocksize;
}
/* full blocks */
if (inl > (unsigned int) cipher_ctx->blocksize) {
nblocks = inl/cipher_ctx->blocksize;
len = nblocks * cipher_ctx->blocksize;
if (cipher_do_cipher(ctx, out, in, len) < 1)
return 0;
inl -= len;
out += len;
in += len;
}
/* final partial block */
if (inl) {
memset(cipher_ctx->partial, 0, cipher_ctx->blocksize);
if (cipher_do_cipher(ctx, cipher_ctx->partial, cipher_ctx->partial,
cipher_ctx->blocksize) < 1)
return 0;
while (inl--) {
out[cipher_ctx->num] = in[cipher_ctx->num]
^ cipher_ctx->partial[cipher_ctx->num];
cipher_ctx->num++;
}
}
return 1;
}
static int cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void* p2)
{
struct cipher_ctx *cipher_ctx =
(struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
EVP_CIPHER_CTX *to_ctx = (EVP_CIPHER_CTX *)p2;
struct cipher_ctx *to_cipher_ctx;
switch (type) {
case EVP_CTRL_COPY:
if (cipher_ctx == NULL)
return 1;
/* when copying the context, a new session needs to be initialized */
to_cipher_ctx =
(struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(to_ctx);
memset(&to_cipher_ctx->sess, 0, sizeof(to_cipher_ctx->sess));
return cipher_init(to_ctx, cipher_ctx->sess.key, EVP_CIPHER_CTX_iv(ctx),
(cipher_ctx->op == COP_ENCRYPT));
case EVP_CTRL_INIT:
memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess));
return 1;
default:
break;
}
return -1;
}
static int cipher_cleanup(EVP_CIPHER_CTX *ctx)
{
struct cipher_ctx *cipher_ctx =
(struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
return clean_devcrypto_session(&cipher_ctx->sess);
}
/*
* Keep a table of known nids and associated methods.
* Note that known_cipher_nids[] isn't necessarily indexed the same way as
* cipher_data[] above, which known_cipher_methods[] is.
*/
static int known_cipher_nids[OSSL_NELEM(cipher_data)];
static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */
static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = { NULL, };
static void prepare_cipher_methods(void)
{
size_t i;
struct session_op sess;
unsigned long cipher_mode;
memset(&sess, 0, sizeof(sess));
sess.key = (void *)"01234567890123456789012345678901234567890123456789";
for (i = 0, known_cipher_nids_amount = 0;
i < OSSL_NELEM(cipher_data); i++) {
/*
* Check that the algo is really availably by trying to open and close
* a session.
*/
sess.cipher = cipher_data[i].devcryptoid;
sess.keylen = cipher_data[i].keylen;
if (ioctl(cfd, CIOCGSESSION, &sess) < 0
|| ioctl(cfd, CIOCFSESSION, &sess.ses) < 0)
continue;
cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;
if ((known_cipher_methods[i] =
EVP_CIPHER_meth_new(cipher_data[i].nid,
cipher_mode == EVP_CIPH_CTR_MODE ? 1 :
cipher_data[i].blocksize,
cipher_data[i].keylen)) == NULL
|| !EVP_CIPHER_meth_set_iv_length(known_cipher_methods[i],
cipher_data[i].ivlen)
|| !EVP_CIPHER_meth_set_flags(known_cipher_methods[i],
cipher_data[i].flags
| EVP_CIPH_CUSTOM_COPY
| EVP_CIPH_CTRL_INIT
| EVP_CIPH_FLAG_DEFAULT_ASN1)
|| !EVP_CIPHER_meth_set_init(known_cipher_methods[i], cipher_init)
|| !EVP_CIPHER_meth_set_do_cipher(known_cipher_methods[i],
cipher_mode == EVP_CIPH_CTR_MODE ?
ctr_do_cipher :
cipher_do_cipher)
|| !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], cipher_ctrl)
|| !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i],
cipher_cleanup)
|| !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],
sizeof(struct cipher_ctx))) {
EVP_CIPHER_meth_free(known_cipher_methods[i]);
known_cipher_methods[i] = NULL;
} else {
known_cipher_nids[known_cipher_nids_amount++] =
cipher_data[i].nid;
}
}
}
static const EVP_CIPHER *get_cipher_method(int nid)
{
size_t i = get_cipher_data_index(nid);
if (i == (size_t)-1)
return NULL;
return known_cipher_methods[i];
}
static int get_cipher_nids(const int **nids)
{
*nids = known_cipher_nids;
return known_cipher_nids_amount;
}
static void destroy_cipher_method(int nid)
{
size_t i = get_cipher_data_index(nid);
EVP_CIPHER_meth_free(known_cipher_methods[i]);
known_cipher_methods[i] = NULL;
}
static void destroy_all_cipher_methods(void)
{
size_t i;
for (i = 0; i < OSSL_NELEM(cipher_data); i++)
destroy_cipher_method(cipher_data[i].nid);
}
static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
const int **nids, int nid)
{
if (cipher == NULL)
return get_cipher_nids(nids);
*cipher = get_cipher_method(nid);
return *cipher != NULL;
}
/*
* We only support digests if the cryptodev implementation supports multiple
* data updates and session copying. Otherwise, we would be forced to maintain
* a cache, which is perilous if there's a lot of data coming in (if someone
* wants to checksum an OpenSSL tarball, for example).
*/
#if defined(CIOCCPHASH) && defined(COP_FLAG_UPDATE) && defined(COP_FLAG_FINAL)
#define IMPLEMENT_DIGEST
/******************************************************************************
*
* Digests
*
* Because they all do the same basic operation, we have only one set of
* method functions for them all to share, and a mapping table between
* NIDs and cryptodev IDs, with all the necessary size data.
*
*****/
struct digest_ctx {
struct session_op sess;
/* This signals that the init function was called, not that it succeeded. */
int init_called;
};
static const struct digest_data_st {
int nid;
int blocksize;
int digestlen;
int devcryptoid;
} digest_data[] = {
#ifndef OPENSSL_NO_MD5
{ NID_md5, /* MD5_CBLOCK */ 64, 16, CRYPTO_MD5 },
#endif
{ NID_sha1, SHA_CBLOCK, 20, CRYPTO_SHA1 },
#ifndef OPENSSL_NO_RMD160
# if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_RIPEMD160)
{ NID_ripemd160, /* RIPEMD160_CBLOCK */ 64, 20, CRYPTO_RIPEMD160 },
# endif
#endif
#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_224)
{ NID_sha224, SHA256_CBLOCK, 224 / 8, CRYPTO_SHA2_224 },
#endif
#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_256)
{ NID_sha256, SHA256_CBLOCK, 256 / 8, CRYPTO_SHA2_256 },
#endif
#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_384)
{ NID_sha384, SHA512_CBLOCK, 384 / 8, CRYPTO_SHA2_384 },
#endif
#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_512)
{ NID_sha512, SHA512_CBLOCK, 512 / 8, CRYPTO_SHA2_512 },
#endif
};
static size_t get_digest_data_index(int nid)
{
size_t i;
for (i = 0; i < OSSL_NELEM(digest_data); i++)
if (nid == digest_data[i].nid)
return i;
/*
* Code further down must make sure that only NIDs in the table above
* are used. If any other NID reaches this function, there's a grave
* coding error further down.
*/
assert("Code that never should be reached" == NULL);
return -1;
}
static const struct digest_data_st *get_digest_data(int nid)
{
return &digest_data[get_digest_data_index(nid)];
}
/*
* Following are the four necessary functions to map OpenSSL functionality
* with cryptodev.
*/
static int digest_init(EVP_MD_CTX *ctx)
{
struct digest_ctx *digest_ctx =
(struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
const struct digest_data_st *digest_d =
get_digest_data(EVP_MD_CTX_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(SYS_F_IOCTL, errno);
return 0;
}
return 1;
}
static int digest_op(struct digest_ctx *ctx, const void *src, size_t srclen,
void *res, unsigned int flags)
{
struct crypt_op cryp;
memset(&cryp, 0, sizeof(cryp));
cryp.ses = ctx->sess.ses;
cryp.len = srclen;
cryp.src = (void *)src;
cryp.dst = NULL;
cryp.mac = res;
cryp.flags = flags;
return ioctl(cfd, CIOCCRYPT, &cryp);
}
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);
if (count == 0)
return 1;
if (digest_ctx == NULL)
return 0;
if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) < 0) {
SYSerr(SYS_F_IOCTL, errno);
return 0;
}
return 1;
}
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);
if (md == NULL || digest_ctx == NULL)
return 0;
if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
SYSerr(SYS_F_IOCTL, errno);
return 0;
}
return 1;
}
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 *digest_to =
(struct digest_ctx *)EVP_MD_CTX_md_data(to);
struct cphash_op cphash;
if (digest_from == NULL || digest_from->init_called != 1)
return 1;
if (!digest_init(to)) {
SYSerr(SYS_F_IOCTL, errno);
return 0;
}
cphash.src_ses = digest_from->sess.ses;
cphash.dst_ses = digest_to->sess.ses;
if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
SYSerr(SYS_F_IOCTL, errno);
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);
if (digest_ctx == NULL)
return 1;
return clean_devcrypto_session(&digest_ctx->sess);
}
static int devcrypto_test_digest(size_t digest_data_index)
{
struct session_op sess1, sess2;
struct cphash_op cphash;
int ret=0;
memset(&sess1, 0, sizeof(sess1));
memset(&sess2, 0, sizeof(sess2));
sess1.mac = digest_data[digest_data_index].devcryptoid;
if (ioctl(cfd, CIOCGSESSION, &sess1) < 0)
return 0;
/* Make sure the driver is capable of hash state copy */
sess2.mac = sess1.mac;
if (ioctl(cfd, CIOCGSESSION, &sess2) >= 0) {
cphash.src_ses = sess1.ses;
cphash.dst_ses = sess2.ses;
if (ioctl(cfd, CIOCCPHASH, &cphash) >= 0)
ret = 1;
ioctl(cfd, CIOCFSESSION, &sess2.ses);
}
ioctl(cfd, CIOCFSESSION, &sess1.ses);
return ret;
}
/*
* Keep a table of known nids and associated methods.
* Note that known_digest_nids[] isn't necessarily indexed the same way as
* digest_data[] above, which known_digest_methods[] is.
*/
static int known_digest_nids[OSSL_NELEM(digest_data)];
static int known_digest_nids_amount = -1; /* -1 indicates not yet initialised */
static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = { NULL, };
static void prepare_digest_methods(void)
{
size_t i;
for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data);
i++) {
/*
* Check that the algo is usable
*/
if (!devcrypto_test_digest(i))
continue;
if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,
NID_undef)) == NULL
|| !EVP_MD_meth_set_input_blocksize(known_digest_methods[i],
digest_data[i].blocksize)
|| !EVP_MD_meth_set_result_size(known_digest_methods[i],
digest_data[i].digestlen)
|| !EVP_MD_meth_set_init(known_digest_methods[i], digest_init)
|| !EVP_MD_meth_set_update(known_digest_methods[i], digest_update)
|| !EVP_MD_meth_set_final(known_digest_methods[i], digest_final)
|| !EVP_MD_meth_set_copy(known_digest_methods[i], digest_copy)
|| !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)
|| !EVP_MD_meth_set_app_datasize(known_digest_methods[i],
sizeof(struct digest_ctx))) {
EVP_MD_meth_free(known_digest_methods[i]);
known_digest_methods[i] = NULL;
} else {
known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
}
}
}
static const EVP_MD *get_digest_method(int nid)
{
size_t i = get_digest_data_index(nid);
if (i == (size_t)-1)
return NULL;
return known_digest_methods[i];
}
static int get_digest_nids(const int **nids)
{
*nids = known_digest_nids;
return known_digest_nids_amount;
}
static void destroy_digest_method(int nid)
{
size_t i = get_digest_data_index(nid);
EVP_MD_meth_free(known_digest_methods[i]);
known_digest_methods[i] = NULL;
}
static void destroy_all_digest_methods(void)
{
size_t i;
for (i = 0; i < OSSL_NELEM(digest_data); i++)
destroy_digest_method(digest_data[i].nid);
}
static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
const int **nids, int nid)
{
if (digest == NULL)
return get_digest_nids(nids);
*digest = get_digest_method(nid);
return *digest != NULL;
}
#endif
/******************************************************************************
*
* LOAD / UNLOAD
*
*****/
static int devcrypto_unload(ENGINE *e)
{
destroy_all_cipher_methods();
#ifdef IMPLEMENT_DIGEST
destroy_all_digest_methods();
#endif
close(cfd);
return 1;
}
/*
* This engine is always built into libcrypto, so it doesn't offer any
* ability to be dynamically loadable.
*/
void engine_load_devcrypto_int()
{
ENGINE *e = NULL;
if ((cfd = open("/dev/crypto", O_RDWR, 0)) < 0) {
#ifndef ENGINE_DEVCRYPTO_DEBUG
if (errno != ENOENT)
#endif
fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
return;
}
if ((e = ENGINE_new()) == NULL
|| !ENGINE_set_destroy_function(e, devcrypto_unload)) {
ENGINE_free(e);
/*
* We know that devcrypto_unload() won't be called when one of the
* above two calls have failed, so we close cfd explicitly here to
* avoid leaking resources.
*/
close(cfd);
return;
}
prepare_cipher_methods();
#ifdef IMPLEMENT_DIGEST
prepare_digest_methods();
#endif
if (!ENGINE_set_id(e, "devcrypto")
|| !ENGINE_set_name(e, "/dev/crypto engine")
/*
* Asymmetric ciphers aren't well supported with /dev/crypto. Among the BSD
* implementations, it seems to only exist in FreeBSD, and regarding the
* parameters in its crypt_kop, the manual crypto(4) has this to say:
*
* The semantics of these arguments are currently undocumented.
*
* Reading through the FreeBSD source code doesn't give much more than
* their CRK_MOD_EXP implementation for ubsec.
*
* It doesn't look much better with cryptodev-linux. They have the crypt_kop
* structure as well as the command (CRK_*) in cryptodev.h, but no support
* seems to be implemented at all for the moment.
*
* At the time of writing, it seems impossible to write proper support for
* FreeBSD's asym features without some very deep knowledge and access to
* specific kernel modules.
*
* /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
# ifndef OPENSSL_NO_DH
|| !ENGINE_set_DH(e, devcrypto_dh)
# endif
# ifndef OPENSSL_NO_EC
|| !ENGINE_set_EC(e, devcrypto_ec)
# endif
#endif
|| !ENGINE_set_ciphers(e, devcrypto_ciphers)
#ifdef IMPLEMENT_DIGEST
|| !ENGINE_set_digests(e, devcrypto_digests)
#endif
) {
ENGINE_free(e);
return;
}
ENGINE_add(e);
ENGINE_free(e); /* Loose our local reference */
ERR_clear_error();
}

View file

@ -0,0 +1,510 @@
/*
* Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
#include "internal/dso.h"
#include <openssl/crypto.h>
/*
* Shared libraries implementing ENGINEs for use by the "dynamic" ENGINE
* loader should implement the hook-up functions with the following
* prototypes.
*/
/* Our ENGINE handlers */
static int dynamic_init(ENGINE *e);
static int dynamic_finish(ENGINE *e);
static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p,
void (*f) (void));
/* Predeclare our context type */
typedef struct st_dynamic_data_ctx dynamic_data_ctx;
/* The implementation for the important control command */
static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx);
#define DYNAMIC_CMD_SO_PATH ENGINE_CMD_BASE
#define DYNAMIC_CMD_NO_VCHECK (ENGINE_CMD_BASE + 1)
#define DYNAMIC_CMD_ID (ENGINE_CMD_BASE + 2)
#define DYNAMIC_CMD_LIST_ADD (ENGINE_CMD_BASE + 3)
#define DYNAMIC_CMD_DIR_LOAD (ENGINE_CMD_BASE + 4)
#define DYNAMIC_CMD_DIR_ADD (ENGINE_CMD_BASE + 5)
#define DYNAMIC_CMD_LOAD (ENGINE_CMD_BASE + 6)
/* The constants used when creating the ENGINE */
static const char *engine_dynamic_id = "dynamic";
static const char *engine_dynamic_name = "Dynamic engine loading support";
static const ENGINE_CMD_DEFN dynamic_cmd_defns[] = {
{DYNAMIC_CMD_SO_PATH,
"SO_PATH",
"Specifies the path to the new ENGINE shared library",
ENGINE_CMD_FLAG_STRING},
{DYNAMIC_CMD_NO_VCHECK,
"NO_VCHECK",
"Specifies to continue even if version checking fails (boolean)",
ENGINE_CMD_FLAG_NUMERIC},
{DYNAMIC_CMD_ID,
"ID",
"Specifies an ENGINE id name for loading",
ENGINE_CMD_FLAG_STRING},
{DYNAMIC_CMD_LIST_ADD,
"LIST_ADD",
"Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)",
ENGINE_CMD_FLAG_NUMERIC},
{DYNAMIC_CMD_DIR_LOAD,
"DIR_LOAD",
"Specifies whether to load from 'DIR_ADD' directories (0=no,1=yes,2=mandatory)",
ENGINE_CMD_FLAG_NUMERIC},
{DYNAMIC_CMD_DIR_ADD,
"DIR_ADD",
"Adds a directory from which ENGINEs can be loaded",
ENGINE_CMD_FLAG_STRING},
{DYNAMIC_CMD_LOAD,
"LOAD",
"Load up the ENGINE specified by other settings",
ENGINE_CMD_FLAG_NO_INPUT},
{0, NULL, NULL, 0}
};
/*
* Loading code stores state inside the ENGINE structure via the "ex_data"
* element. We load all our state into a single structure and use that as a
* single context in the "ex_data" stack.
*/
struct st_dynamic_data_ctx {
/* The DSO object we load that supplies the ENGINE code */
DSO *dynamic_dso;
/*
* The function pointer to the version checking shared library function
*/
dynamic_v_check_fn v_check;
/*
* The function pointer to the engine-binding shared library function
*/
dynamic_bind_engine bind_engine;
/* The default name/path for loading the shared library */
char *DYNAMIC_LIBNAME;
/* Whether to continue loading on a version check failure */
int no_vcheck;
/* If non-NULL, stipulates the 'id' of the ENGINE to be loaded */
char *engine_id;
/*
* If non-zero, a successfully loaded ENGINE should be added to the
* internal ENGINE list. If 2, the add must succeed or the entire load
* should fail.
*/
int list_add_value;
/* The symbol name for the version checking function */
const char *DYNAMIC_F1;
/* The symbol name for the "initialise ENGINE structure" function */
const char *DYNAMIC_F2;
/*
* Whether to never use 'dirs', use 'dirs' as a fallback, or only use
* 'dirs' for loading. Default is to use 'dirs' as a fallback.
*/
int dir_load;
/* A stack of directories from which ENGINEs could be loaded */
STACK_OF(OPENSSL_STRING) *dirs;
};
/*
* This is the "ex_data" index we obtain and reserve for use with our context
* structure.
*/
static int dynamic_ex_data_idx = -1;
static void int_free_str(char *s)
{
OPENSSL_free(s);
}
/*
* Because our ex_data element may or may not get allocated depending on
* whether a "first-use" occurs before the ENGINE is freed, we have a memory
* leak problem to solve. We can't declare a "new" handler for the ex_data as
* we don't want a dynamic_data_ctx in *all* ENGINE structures of all types
* (this is a bug in the design of CRYPTO_EX_DATA). As such, we just declare
* a "free" handler and that will get called if an ENGINE is being destroyed
* and there was an ex_data element corresponding to our context type.
*/
static void dynamic_data_ctx_free_func(void *parent, void *ptr,
CRYPTO_EX_DATA *ad, int idx, long argl,
void *argp)
{
if (ptr) {
dynamic_data_ctx *ctx = (dynamic_data_ctx *)ptr;
DSO_free(ctx->dynamic_dso);
OPENSSL_free(ctx->DYNAMIC_LIBNAME);
OPENSSL_free(ctx->engine_id);
sk_OPENSSL_STRING_pop_free(ctx->dirs, int_free_str);
OPENSSL_free(ctx);
}
}
/*
* Construct the per-ENGINE context. We create it blindly and then use a lock
* to check for a race - if so, all but one of the threads "racing" will have
* wasted their time. The alternative involves creating everything inside the
* lock which is far worse.
*/
static int dynamic_set_data_ctx(ENGINE *e, dynamic_data_ctx **ctx)
{
dynamic_data_ctx *c = OPENSSL_zalloc(sizeof(*c));
int ret = 1;
if (c == NULL) {
ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE);
return 0;
}
c->dirs = sk_OPENSSL_STRING_new_null();
if (c->dirs == NULL) {
ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE);
OPENSSL_free(c);
return 0;
}
c->DYNAMIC_F1 = "v_check";
c->DYNAMIC_F2 = "bind_engine";
c->dir_load = 1;
CRYPTO_THREAD_write_lock(global_engine_lock);
if ((*ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e,
dynamic_ex_data_idx))
== NULL) {
/* Good, we're the first */
ret = ENGINE_set_ex_data(e, dynamic_ex_data_idx, c);
if (ret) {
*ctx = c;
c = NULL;
}
}
CRYPTO_THREAD_unlock(global_engine_lock);
/*
* If we lost the race to set the context, c is non-NULL and *ctx is the
* context of the thread that won.
*/
if (c)
sk_OPENSSL_STRING_free(c->dirs);
OPENSSL_free(c);
return ret;
}
/*
* This function retrieves the context structure from an ENGINE's "ex_data",
* or if it doesn't exist yet, sets it up.
*/
static dynamic_data_ctx *dynamic_get_data_ctx(ENGINE *e)
{
dynamic_data_ctx *ctx;
if (dynamic_ex_data_idx < 0) {
/*
* Create and register the ENGINE ex_data, and associate our "free"
* function with it to ensure any allocated contexts get freed when
* an ENGINE goes underground.
*/
int new_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL,
dynamic_data_ctx_free_func);
if (new_idx == -1) {
ENGINEerr(ENGINE_F_DYNAMIC_GET_DATA_CTX, ENGINE_R_NO_INDEX);
return NULL;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
/* Avoid a race by checking again inside this lock */
if (dynamic_ex_data_idx < 0) {
/* Good, someone didn't beat us to it */
dynamic_ex_data_idx = new_idx;
new_idx = -1;
}
CRYPTO_THREAD_unlock(global_engine_lock);
/*
* In theory we could "give back" the index here if (new_idx>-1), but
* it's not possible and wouldn't gain us much if it were.
*/
}
ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, dynamic_ex_data_idx);
/* Check if the context needs to be created */
if ((ctx == NULL) && !dynamic_set_data_ctx(e, &ctx))
/* "set_data" will set errors if necessary */
return NULL;
return ctx;
}
static ENGINE *engine_dynamic(void)
{
ENGINE *ret = ENGINE_new();
if (ret == NULL)
return NULL;
if (!ENGINE_set_id(ret, engine_dynamic_id) ||
!ENGINE_set_name(ret, engine_dynamic_name) ||
!ENGINE_set_init_function(ret, dynamic_init) ||
!ENGINE_set_finish_function(ret, dynamic_finish) ||
!ENGINE_set_ctrl_function(ret, dynamic_ctrl) ||
!ENGINE_set_flags(ret, ENGINE_FLAGS_BY_ID_COPY) ||
!ENGINE_set_cmd_defns(ret, dynamic_cmd_defns)) {
ENGINE_free(ret);
return NULL;
}
return ret;
}
void engine_load_dynamic_int(void)
{
ENGINE *toadd = engine_dynamic();
if (!toadd)
return;
ENGINE_add(toadd);
/*
* If the "add" worked, it gets a structural reference. So either way, we
* release our just-created reference.
*/
ENGINE_free(toadd);
/*
* 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_clear_error();
}
static int dynamic_init(ENGINE *e)
{
/*
* We always return failure - the "dynamic" engine itself can't be used
* for anything.
*/
return 0;
}
static int dynamic_finish(ENGINE *e)
{
/*
* This should never be called on account of "dynamic_init" always
* failing.
*/
return 0;
}
static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
{
dynamic_data_ctx *ctx = dynamic_get_data_ctx(e);
int initialised;
if (!ctx) {
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_NOT_LOADED);
return 0;
}
initialised = ((ctx->dynamic_dso == NULL) ? 0 : 1);
/* All our control commands require the ENGINE to be uninitialised */
if (initialised) {
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_ALREADY_LOADED);
return 0;
}
switch (cmd) {
case DYNAMIC_CMD_SO_PATH:
/* a NULL 'p' or a string of zero-length is the same thing */
if (p && (strlen((const char *)p) < 1))
p = NULL;
OPENSSL_free(ctx->DYNAMIC_LIBNAME);
if (p)
ctx->DYNAMIC_LIBNAME = OPENSSL_strdup(p);
else
ctx->DYNAMIC_LIBNAME = NULL;
return (ctx->DYNAMIC_LIBNAME ? 1 : 0);
case DYNAMIC_CMD_NO_VCHECK:
ctx->no_vcheck = ((i == 0) ? 0 : 1);
return 1;
case DYNAMIC_CMD_ID:
/* a NULL 'p' or a string of zero-length is the same thing */
if (p && (strlen((const char *)p) < 1))
p = NULL;
OPENSSL_free(ctx->engine_id);
if (p)
ctx->engine_id = OPENSSL_strdup(p);
else
ctx->engine_id = NULL;
return (ctx->engine_id ? 1 : 0);
case DYNAMIC_CMD_LIST_ADD:
if ((i < 0) || (i > 2)) {
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT);
return 0;
}
ctx->list_add_value = (int)i;
return 1;
case DYNAMIC_CMD_LOAD:
return dynamic_load(e, ctx);
case DYNAMIC_CMD_DIR_LOAD:
if ((i < 0) || (i > 2)) {
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT);
return 0;
}
ctx->dir_load = (int)i;
return 1;
case DYNAMIC_CMD_DIR_ADD:
/* a NULL 'p' or a string of zero-length is the same thing */
if (!p || (strlen((const char *)p) < 1)) {
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT);
return 0;
}
{
char *tmp_str = OPENSSL_strdup(p);
if (tmp_str == NULL) {
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ERR_R_MALLOC_FAILURE);
return 0;
}
if (!sk_OPENSSL_STRING_push(ctx->dirs, tmp_str)) {
OPENSSL_free(tmp_str);
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ERR_R_MALLOC_FAILURE);
return 0;
}
}
return 1;
default:
break;
}
ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
return 0;
}
static int int_load(dynamic_data_ctx *ctx)
{
int num, loop;
/* Unless told not to, try a direct load */
if ((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso,
ctx->DYNAMIC_LIBNAME, NULL,
0)) != NULL)
return 1;
/* If we're not allowed to use 'dirs' or we have none, fail */
if (!ctx->dir_load || (num = sk_OPENSSL_STRING_num(ctx->dirs)) < 1)
return 0;
for (loop = 0; loop < num; loop++) {
const char *s = sk_OPENSSL_STRING_value(ctx->dirs, loop);
char *merge = DSO_merge(ctx->dynamic_dso, ctx->DYNAMIC_LIBNAME, s);
if (!merge)
return 0;
if (DSO_load(ctx->dynamic_dso, merge, NULL, 0)) {
/* Found what we're looking for */
OPENSSL_free(merge);
return 1;
}
OPENSSL_free(merge);
}
return 0;
}
static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx)
{
ENGINE cpy;
dynamic_fns fns;
if (ctx->dynamic_dso == NULL)
ctx->dynamic_dso = DSO_new();
if (ctx->dynamic_dso == NULL)
return 0;
if (!ctx->DYNAMIC_LIBNAME) {
if (!ctx->engine_id)
return 0;
DSO_ctrl(ctx->dynamic_dso, DSO_CTRL_SET_FLAGS,
DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL);
ctx->DYNAMIC_LIBNAME =
DSO_convert_filename(ctx->dynamic_dso, ctx->engine_id);
}
if (!int_load(ctx)) {
ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_NOT_FOUND);
DSO_free(ctx->dynamic_dso);
ctx->dynamic_dso = NULL;
return 0;
}
/* We have to find a bind function otherwise it'll always end badly */
if (!
(ctx->bind_engine =
(dynamic_bind_engine) DSO_bind_func(ctx->dynamic_dso,
ctx->DYNAMIC_F2))) {
ctx->bind_engine = NULL;
DSO_free(ctx->dynamic_dso);
ctx->dynamic_dso = NULL;
ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_FAILURE);
return 0;
}
/* Do we perform version checking? */
if (!ctx->no_vcheck) {
unsigned long vcheck_res = 0;
/*
* Now we try to find a version checking function and decide how to
* cope with failure if/when it fails.
*/
ctx->v_check =
(dynamic_v_check_fn) DSO_bind_func(ctx->dynamic_dso,
ctx->DYNAMIC_F1);
if (ctx->v_check)
vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION);
/*
* We fail if the version checker veto'd the load *or* if it is
* deferring to us (by returning its version) and we think it is too
* old.
*/
if (vcheck_res < OSSL_DYNAMIC_OLDEST) {
/* Fail */
ctx->bind_engine = NULL;
ctx->v_check = NULL;
DSO_free(ctx->dynamic_dso);
ctx->dynamic_dso = NULL;
ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
ENGINE_R_VERSION_INCOMPATIBILITY);
return 0;
}
}
/*
* First binary copy the ENGINE structure so that we can roll back if the
* hand-over fails
*/
memcpy(&cpy, e, sizeof(ENGINE));
/*
* Provide the ERR, "ex_data", memory, and locking callbacks so the
* loaded library uses our state rather than its own. FIXME: As noted in
* engine.h, much of this would be simplified if each area of code
* provided its own "summary" structure of all related callbacks. It
* would also increase opaqueness.
*/
fns.static_state = ENGINE_get_static_state();
CRYPTO_get_mem_functions(&fns.mem_fns.malloc_fn, &fns.mem_fns.realloc_fn,
&fns.mem_fns.free_fn);
/*
* Now that we've loaded the dynamic engine, make sure no "dynamic"
* ENGINE elements will show through.
*/
engine_set_all_null(e);
/* Try to bind the ENGINE onto our own ENGINE structure */
if (!ctx->bind_engine(e, ctx->engine_id, &fns)) {
ctx->bind_engine = NULL;
ctx->v_check = NULL;
DSO_free(ctx->dynamic_dso);
ctx->dynamic_dso = NULL;
ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_INIT_FAILED);
/* Copy the original ENGINE structure back */
memcpy(e, &cpy, sizeof(ENGINE));
return 0;
}
/* Do we try to add this ENGINE to the internal list too? */
if (ctx->list_add_value > 0) {
if (!ENGINE_add(e)) {
/* Do we tolerate this or fail? */
if (ctx->list_add_value > 1) {
/*
* Fail - NB: By this time, it's too late to rollback, and
* trying to do so allows the bind_engine() code to have
* created leaks. We just have to fail where we are, after
* the ENGINE has changed.
*/
ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
ENGINE_R_CONFLICTING_ENGINE_ID);
return 0;
}
/* Tolerate */
ERR_clear_error();
}
}
return 1;
}

View file

@ -0,0 +1,154 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 <openssl/err.h>
#include <openssl/engineerr.h>
#ifndef OPENSSL_NO_ERR
static const ERR_STRING_DATA ENGINE_str_functs[] = {
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_DIGEST_UPDATE, 0), "digest_update"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_DYNAMIC_CTRL, 0), "dynamic_ctrl"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_DYNAMIC_GET_DATA_CTX, 0),
"dynamic_get_data_ctx"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_DYNAMIC_LOAD, 0), "dynamic_load"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_DYNAMIC_SET_DATA_CTX, 0),
"dynamic_set_data_ctx"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_ADD, 0), "ENGINE_add"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_BY_ID, 0), "ENGINE_by_id"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_CMD_IS_EXECUTABLE, 0),
"ENGINE_cmd_is_executable"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_CTRL, 0), "ENGINE_ctrl"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_CTRL_CMD, 0), "ENGINE_ctrl_cmd"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_CTRL_CMD_STRING, 0),
"ENGINE_ctrl_cmd_string"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_FINISH, 0), "ENGINE_finish"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_CIPHER, 0),
"ENGINE_get_cipher"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_DIGEST, 0),
"ENGINE_get_digest"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_FIRST, 0),
"ENGINE_get_first"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_LAST, 0), "ENGINE_get_last"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_NEXT, 0), "ENGINE_get_next"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_PKEY_ASN1_METH, 0),
"ENGINE_get_pkey_asn1_meth"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_PKEY_METH, 0),
"ENGINE_get_pkey_meth"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_GET_PREV, 0), "ENGINE_get_prev"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_INIT, 0), "ENGINE_init"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_LIST_ADD, 0), "engine_list_add"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_LIST_REMOVE, 0),
"engine_list_remove"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_LOAD_PRIVATE_KEY, 0),
"ENGINE_load_private_key"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_LOAD_PUBLIC_KEY, 0),
"ENGINE_load_public_key"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT, 0),
"ENGINE_load_ssl_client_cert"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_NEW, 0), "ENGINE_new"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_PKEY_ASN1_FIND_STR, 0),
"ENGINE_pkey_asn1_find_str"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_REMOVE, 0), "ENGINE_remove"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_SET_DEFAULT_STRING, 0),
"ENGINE_set_default_string"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_SET_ID, 0), "ENGINE_set_id"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_SET_NAME, 0), "ENGINE_set_name"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_TABLE_REGISTER, 0),
"engine_table_register"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_UNLOCKED_FINISH, 0),
"engine_unlocked_finish"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_ENGINE_UP_REF, 0), "ENGINE_up_ref"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_INT_CLEANUP_ITEM, 0),
"int_cleanup_item"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_INT_CTRL_HELPER, 0), "int_ctrl_helper"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_INT_ENGINE_CONFIGURE, 0),
"int_engine_configure"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_INT_ENGINE_MODULE_INIT, 0),
"int_engine_module_init"},
{ERR_PACK(ERR_LIB_ENGINE, ENGINE_F_OSSL_HMAC_INIT, 0), "ossl_hmac_init"},
{0, NULL}
};
static const ERR_STRING_DATA ENGINE_str_reasons[] = {
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_ALREADY_LOADED), "already loaded"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER),
"argument is not a number"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_CMD_NOT_EXECUTABLE),
"cmd not executable"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_COMMAND_TAKES_INPUT),
"command takes input"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_COMMAND_TAKES_NO_INPUT),
"command takes no input"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_CONFLICTING_ENGINE_ID),
"conflicting engine id"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED),
"ctrl command not implemented"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_DSO_FAILURE), "DSO failure"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_DSO_NOT_FOUND), "dso not found"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_ENGINES_SECTION_ERROR),
"engines section error"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_ENGINE_CONFIGURATION_ERROR),
"engine configuration error"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_ENGINE_IS_NOT_IN_LIST),
"engine is not in the list"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_ENGINE_SECTION_ERROR),
"engine section error"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_FAILED_LOADING_PRIVATE_KEY),
"failed loading private key"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_FAILED_LOADING_PUBLIC_KEY),
"failed loading public key"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_FINISH_FAILED), "finish failed"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_ID_OR_NAME_MISSING),
"'id' or 'name' missing"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_INIT_FAILED), "init failed"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_INTERNAL_LIST_ERROR),
"internal list error"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_INVALID_ARGUMENT),
"invalid argument"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_INVALID_CMD_NAME),
"invalid cmd name"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_INVALID_CMD_NUMBER),
"invalid cmd number"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_INVALID_INIT_VALUE),
"invalid init value"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_INVALID_STRING), "invalid string"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_NOT_INITIALISED), "not initialised"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_NOT_LOADED), "not loaded"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_NO_CONTROL_FUNCTION),
"no control function"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_NO_INDEX), "no index"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_NO_LOAD_FUNCTION),
"no load function"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_NO_REFERENCE), "no reference"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_NO_SUCH_ENGINE), "no such engine"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_UNIMPLEMENTED_CIPHER),
"unimplemented cipher"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_UNIMPLEMENTED_DIGEST),
"unimplemented digest"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD),
"unimplemented public key method"},
{ERR_PACK(ERR_LIB_ENGINE, 0, ENGINE_R_VERSION_INCOMPATIBILITY),
"version incompatibility"},
{0, NULL}
};
#endif
int ERR_load_ENGINE_strings(void)
{
#ifndef OPENSSL_NO_ERR
if (ERR_func_error_string(ENGINE_str_functs[0].error) == NULL) {
ERR_load_strings_const(ENGINE_str_functs);
ERR_load_strings_const(ENGINE_str_reasons);
}
#endif
return 1;
}

View file

@ -0,0 +1,123 @@
/*
* Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
*
* Licensed under the OpenSSL license (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 "eng_int.h"
#include <openssl/conf.h>
int ENGINE_set_default(ENGINE *e, unsigned int flags)
{
if ((flags & ENGINE_METHOD_CIPHERS) && !ENGINE_set_default_ciphers(e))
return 0;
if ((flags & ENGINE_METHOD_DIGESTS) && !ENGINE_set_default_digests(e))
return 0;
#ifndef OPENSSL_NO_RSA
if ((flags & ENGINE_METHOD_RSA) && !ENGINE_set_default_RSA(e))
return 0;
#endif
#ifndef OPENSSL_NO_DSA
if ((flags & ENGINE_METHOD_DSA) && !ENGINE_set_default_DSA(e))
return 0;
#endif
#ifndef OPENSSL_NO_DH
if ((flags & ENGINE_METHOD_DH) && !ENGINE_set_default_DH(e))
return 0;
#endif
#ifndef OPENSSL_NO_EC
if ((flags & ENGINE_METHOD_EC) && !ENGINE_set_default_EC(e))
return 0;
#endif
if ((flags & ENGINE_METHOD_RAND) && !ENGINE_set_default_RAND(e))
return 0;
if ((flags & ENGINE_METHOD_PKEY_METHS)
&& !ENGINE_set_default_pkey_meths(e))
return 0;
if ((flags & ENGINE_METHOD_PKEY_ASN1_METHS)
&& !ENGINE_set_default_pkey_asn1_meths(e))
return 0;
return 1;
}
/* Set default algorithms using a string */
static int int_def_cb(const char *alg, int len, void *arg)
{
unsigned int *pflags = arg;
if (alg == NULL)
return 0;
if (strncmp(alg, "ALL", len) == 0)
*pflags |= ENGINE_METHOD_ALL;
else if (strncmp(alg, "RSA", len) == 0)
*pflags |= ENGINE_METHOD_RSA;
else if (strncmp(alg, "DSA", len) == 0)
*pflags |= ENGINE_METHOD_DSA;
else if (strncmp(alg, "DH", len) == 0)
*pflags |= ENGINE_METHOD_DH;
else if (strncmp(alg, "EC", len) == 0)
*pflags |= ENGINE_METHOD_EC;
else if (strncmp(alg, "RAND", len) == 0)
*pflags |= ENGINE_METHOD_RAND;
else if (strncmp(alg, "CIPHERS", len) == 0)
*pflags |= ENGINE_METHOD_CIPHERS;
else if (strncmp(alg, "DIGESTS", len) == 0)
*pflags |= ENGINE_METHOD_DIGESTS;
else if (strncmp(alg, "PKEY", len) == 0)
*pflags |= ENGINE_METHOD_PKEY_METHS | ENGINE_METHOD_PKEY_ASN1_METHS;
else if (strncmp(alg, "PKEY_CRYPTO", len) == 0)
*pflags |= ENGINE_METHOD_PKEY_METHS;
else if (strncmp(alg, "PKEY_ASN1", len) == 0)
*pflags |= ENGINE_METHOD_PKEY_ASN1_METHS;
else
return 0;
return 1;
}
int ENGINE_set_default_string(ENGINE *e, const char *def_list)
{
unsigned int flags = 0;
if (!CONF_parse_list(def_list, ',', 1, int_def_cb, &flags)) {
ENGINEerr(ENGINE_F_ENGINE_SET_DEFAULT_STRING,
ENGINE_R_INVALID_STRING);
ERR_add_error_data(2, "str=", def_list);
return 0;
}
return ENGINE_set_default(e, flags);
}
int ENGINE_register_complete(ENGINE *e)
{
ENGINE_register_ciphers(e);
ENGINE_register_digests(e);
#ifndef OPENSSL_NO_RSA
ENGINE_register_RSA(e);
#endif
#ifndef OPENSSL_NO_DSA
ENGINE_register_DSA(e);
#endif
#ifndef OPENSSL_NO_DH
ENGINE_register_DH(e);
#endif
#ifndef OPENSSL_NO_EC
ENGINE_register_EC(e);
#endif
ENGINE_register_RAND(e);
ENGINE_register_pkey_meths(e);
ENGINE_register_pkey_asn1_meths(e);
return 1;
}
int ENGINE_register_all_complete(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
if (!(e->flags & ENGINE_FLAGS_NO_REGISTER_ALL))
ENGINE_register_complete(e);
return 1;
}

View file

@ -0,0 +1,109 @@
/*
* Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "e_os.h"
#include "eng_int.h"
/*
* Initialise a engine type for use (or up its functional reference count if
* it's already in use). This version is only used internally.
*/
int engine_unlocked_init(ENGINE *e)
{
int to_return = 1;
if ((e->funct_ref == 0) && e->init)
/*
* This is the first functional reference and the engine requires
* initialisation so we do it now.
*/
to_return = e->init(e);
if (to_return) {
/*
* OK, we return a functional reference which is also a structural
* reference.
*/
e->struct_ref++;
e->funct_ref++;
engine_ref_debug(e, 0, 1);
engine_ref_debug(e, 1, 1);
}
return to_return;
}
/*
* Free a functional reference to a engine type. This version is only used
* internally.
*/
int engine_unlocked_finish(ENGINE *e, int unlock_for_handlers)
{
int to_return = 1;
/*
* Reduce the functional reference count here so if it's the terminating
* case, we can release the lock safely and call the finish() handler
* without risk of a race. We get a race if we leave the count until
* after and something else is calling "finish" at the same time -
* there's a chance that both threads will together take the count from 2
* to 0 without either calling finish().
*/
e->funct_ref--;
engine_ref_debug(e, 1, -1);
if ((e->funct_ref == 0) && e->finish) {
if (unlock_for_handlers)
CRYPTO_THREAD_unlock(global_engine_lock);
to_return = e->finish(e);
if (unlock_for_handlers)
CRYPTO_THREAD_write_lock(global_engine_lock);
if (!to_return)
return 0;
}
REF_ASSERT_ISNT(e->funct_ref < 0);
/* Release the structural reference too */
if (!engine_free_util(e, 0)) {
ENGINEerr(ENGINE_F_ENGINE_UNLOCKED_FINISH, ENGINE_R_FINISH_FAILED);
return 0;
}
return to_return;
}
/* The API (locked) version of "init" */
int ENGINE_init(ENGINE *e)
{
int ret;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_INIT, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
ENGINEerr(ENGINE_F_ENGINE_INIT, ERR_R_MALLOC_FAILURE);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
ret = engine_unlocked_init(e);
CRYPTO_THREAD_unlock(global_engine_lock);
return ret;
}
/* The API (locked) version of "finish" */
int ENGINE_finish(ENGINE *e)
{
int to_return = 1;
if (e == NULL)
return 1;
CRYPTO_THREAD_write_lock(global_engine_lock);
to_return = engine_unlocked_finish(e, 1);
CRYPTO_THREAD_unlock(global_engine_lock);
if (!to_return) {
ENGINEerr(ENGINE_F_ENGINE_FINISH, ENGINE_R_FINISH_FAILED);
return 0;
}
return to_return;
}

View file

@ -0,0 +1,171 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
*
* Licensed under the OpenSSL license (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
*/
#ifndef HEADER_ENGINE_INT_H
# define HEADER_ENGINE_INT_H
# include "internal/cryptlib.h"
# include "internal/engine.h"
# include "internal/thread_once.h"
# include "internal/refcount.h"
extern CRYPTO_RWLOCK *global_engine_lock;
/*
* If we compile with this symbol defined, then both reference counts in the
* ENGINE structure will be monitored with a line of output on stderr for
* each change. This prints the engine's pointer address (truncated to
* unsigned int), "struct" or "funct" to indicate the reference type, the
* before and after reference count, and the file:line-number pair. The
* "engine_ref_debug" statements must come *after* the change.
*/
# ifdef ENGINE_REF_COUNT_DEBUG
# define engine_ref_debug(e, isfunct, diff) \
fprintf(stderr, "engine: %08x %s from %d to %d (%s:%d)\n", \
(unsigned int)(e), (isfunct ? "funct" : "struct"), \
((isfunct) ? ((e)->funct_ref - (diff)) : ((e)->struct_ref - (diff))), \
((isfunct) ? (e)->funct_ref : (e)->struct_ref), \
(OPENSSL_FILE), (OPENSSL_LINE))
# else
# define engine_ref_debug(e, isfunct, diff)
# endif
/*
* Any code that will need cleanup operations should use these functions to
* register callbacks. engine_cleanup_int() will call all registered
* callbacks in order. NB: both the "add" functions assume the engine lock to
* already be held (in "write" mode).
*/
typedef void (ENGINE_CLEANUP_CB) (void);
typedef struct st_engine_cleanup_item {
ENGINE_CLEANUP_CB *cb;
} ENGINE_CLEANUP_ITEM;
DEFINE_STACK_OF(ENGINE_CLEANUP_ITEM)
void engine_cleanup_add_first(ENGINE_CLEANUP_CB *cb);
void engine_cleanup_add_last(ENGINE_CLEANUP_CB *cb);
/* We need stacks of ENGINEs for use in eng_table.c */
DEFINE_STACK_OF(ENGINE)
/*
* If this symbol is defined then engine_table_select(), the function that is
* used by RSA, DSA (etc) code to select registered ENGINEs, cache defaults
* and functional references (etc), will display debugging summaries to
* stderr.
*/
/* #define ENGINE_TABLE_DEBUG */
/*
* This represents an implementation table. Dependent code should instantiate
* it as a (ENGINE_TABLE *) pointer value set initially to NULL.
*/
typedef struct st_engine_table ENGINE_TABLE;
int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
ENGINE *e, const int *nids, int num_nids,
int setdefault);
void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e);
void engine_table_cleanup(ENGINE_TABLE **table);
# ifndef ENGINE_TABLE_DEBUG
ENGINE *engine_table_select(ENGINE_TABLE **table, int nid);
# else
ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
int l);
# define engine_table_select(t,n) engine_table_select_tmp(t,n,OPENSSL_FILE,OPENSSL_LINE)
# endif
typedef void (engine_table_doall_cb) (int nid, STACK_OF(ENGINE) *sk,
ENGINE *def, void *arg);
void engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb,
void *arg);
/*
* Internal versions of API functions that have control over locking. These
* are used between C files when functionality needs to be shared but the
* caller may already be controlling of the engine lock.
*/
int engine_unlocked_init(ENGINE *e);
int engine_unlocked_finish(ENGINE *e, int unlock_for_handlers);
int engine_free_util(ENGINE *e, int not_locked);
/*
* This function will reset all "set"able values in an ENGINE to NULL. This
* won't touch reference counts or ex_data, but is equivalent to calling all
* the ENGINE_set_***() functions with a NULL value.
*/
void engine_set_all_null(ENGINE *e);
/*
* NB: Bitwise OR-able values for the "flags" variable in ENGINE are now
* exposed in engine.h.
*/
/* Free up dynamically allocated public key methods associated with ENGINE */
void engine_pkey_meths_free(ENGINE *e);
void engine_pkey_asn1_meths_free(ENGINE *e);
/* Once initialisation function */
extern CRYPTO_ONCE engine_lock_init;
DECLARE_RUN_ONCE(do_engine_lock_init)
/*
* This is a structure for storing implementations of various crypto
* algorithms and functions.
*/
struct engine_st {
const char *id;
const char *name;
const RSA_METHOD *rsa_meth;
const DSA_METHOD *dsa_meth;
const DH_METHOD *dh_meth;
const EC_KEY_METHOD *ec_meth;
const RAND_METHOD *rand_meth;
/* Cipher handling is via this callback */
ENGINE_CIPHERS_PTR ciphers;
/* Digest handling is via this callback */
ENGINE_DIGESTS_PTR digests;
/* Public key handling via this callback */
ENGINE_PKEY_METHS_PTR pkey_meths;
/* ASN1 public key handling via this callback */
ENGINE_PKEY_ASN1_METHS_PTR pkey_asn1_meths;
ENGINE_GEN_INT_FUNC_PTR destroy;
ENGINE_GEN_INT_FUNC_PTR init;
ENGINE_GEN_INT_FUNC_PTR finish;
ENGINE_CTRL_FUNC_PTR ctrl;
ENGINE_LOAD_KEY_PTR load_privkey;
ENGINE_LOAD_KEY_PTR load_pubkey;
ENGINE_SSL_CLIENT_CERT_PTR load_ssl_client_cert;
const ENGINE_CMD_DEFN *cmd_defns;
int flags;
/* reference count on the structure itself */
CRYPTO_REF_COUNT struct_ref;
/*
* reference count on usability of the engine type. NB: This controls the
* loading and initialisation of any functionality required by this
* engine, whereas the previous count is simply to cope with
* (de)allocation of this structure. Hence, running_ref <= struct_ref at
* all times.
*/
int funct_ref;
/* A place to store per-ENGINE data */
CRYPTO_EX_DATA ex_data;
/* Used to maintain the linked-list of engines. */
struct engine_st *prev;
struct engine_st *next;
};
typedef struct st_engine_pile ENGINE_PILE;
DEFINE_LHASH_OF(ENGINE_PILE);
#endif /* HEADER_ENGINE_INT_H */

View file

@ -0,0 +1,299 @@
/*
* Copyright 2001-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "e_os.h"
#include "eng_int.h"
#include <openssl/rand.h>
#include "internal/refcount.h"
CRYPTO_RWLOCK *global_engine_lock;
CRYPTO_ONCE engine_lock_init = CRYPTO_ONCE_STATIC_INIT;
/* The "new"/"free" stuff first */
DEFINE_RUN_ONCE(do_engine_lock_init)
{
if (!OPENSSL_init_crypto(0, NULL))
return 0;
global_engine_lock = CRYPTO_THREAD_lock_new();
return global_engine_lock != NULL;
}
ENGINE *ENGINE_new(void)
{
ENGINE *ret;
if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)
|| (ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
ENGINEerr(ENGINE_F_ENGINE_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
ret->struct_ref = 1;
engine_ref_debug(ret, 0, 1);
if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_ENGINE, ret, &ret->ex_data)) {
OPENSSL_free(ret);
return NULL;
}
return ret;
}
/*
* Placed here (close proximity to ENGINE_new) so that modifications to the
* elements of the ENGINE structure are more likely to be caught and changed
* here.
*/
void engine_set_all_null(ENGINE *e)
{
e->id = NULL;
e->name = NULL;
e->rsa_meth = NULL;
e->dsa_meth = NULL;
e->dh_meth = NULL;
e->rand_meth = NULL;
e->ciphers = NULL;
e->digests = NULL;
e->destroy = NULL;
e->init = NULL;
e->finish = NULL;
e->ctrl = NULL;
e->load_privkey = NULL;
e->load_pubkey = NULL;
e->cmd_defns = NULL;
e->flags = 0;
}
int engine_free_util(ENGINE *e, int not_locked)
{
int i;
if (e == NULL)
return 1;
if (not_locked)
CRYPTO_DOWN_REF(&e->struct_ref, &i, global_engine_lock);
else
i = --e->struct_ref;
engine_ref_debug(e, 0, -1);
if (i > 0)
return 1;
REF_ASSERT_ISNT(i < 0);
/* Free up any dynamically allocated public key methods */
engine_pkey_meths_free(e);
engine_pkey_asn1_meths_free(e);
/*
* Give the ENGINE a chance to do any structural cleanup corresponding to
* allocation it did in its constructor (eg. unload error strings)
*/
if (e->destroy)
e->destroy(e);
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ENGINE, e, &e->ex_data);
OPENSSL_free(e);
return 1;
}
int ENGINE_free(ENGINE *e)
{
return engine_free_util(e, 1);
}
/* Cleanup stuff */
/*
* engine_cleanup_int() is coded such that anything that does work that will
* need cleanup can register a "cleanup" callback here. That way we don't get
* linker bloat by referring to all *possible* cleanups, but any linker bloat
* into code "X" will cause X's cleanup function to end up here.
*/
static STACK_OF(ENGINE_CLEANUP_ITEM) *cleanup_stack = NULL;
static int int_cleanup_check(int create)
{
if (cleanup_stack)
return 1;
if (!create)
return 0;
cleanup_stack = sk_ENGINE_CLEANUP_ITEM_new_null();
return (cleanup_stack ? 1 : 0);
}
static ENGINE_CLEANUP_ITEM *int_cleanup_item(ENGINE_CLEANUP_CB *cb)
{
ENGINE_CLEANUP_ITEM *item;
if ((item = OPENSSL_malloc(sizeof(*item))) == NULL) {
ENGINEerr(ENGINE_F_INT_CLEANUP_ITEM, ERR_R_MALLOC_FAILURE);
return NULL;
}
item->cb = cb;
return item;
}
void engine_cleanup_add_first(ENGINE_CLEANUP_CB *cb)
{
ENGINE_CLEANUP_ITEM *item;
if (!int_cleanup_check(1))
return;
item = int_cleanup_item(cb);
if (item)
sk_ENGINE_CLEANUP_ITEM_insert(cleanup_stack, item, 0);
}
void engine_cleanup_add_last(ENGINE_CLEANUP_CB *cb)
{
ENGINE_CLEANUP_ITEM *item;
if (!int_cleanup_check(1))
return;
item = int_cleanup_item(cb);
if (item != NULL) {
if (sk_ENGINE_CLEANUP_ITEM_push(cleanup_stack, item) <= 0)
OPENSSL_free(item);
}
}
/* The API function that performs all cleanup */
static void engine_cleanup_cb_free(ENGINE_CLEANUP_ITEM *item)
{
(*(item->cb)) ();
OPENSSL_free(item);
}
void engine_cleanup_int(void)
{
if (int_cleanup_check(0)) {
sk_ENGINE_CLEANUP_ITEM_pop_free(cleanup_stack,
engine_cleanup_cb_free);
cleanup_stack = NULL;
}
CRYPTO_THREAD_lock_free(global_engine_lock);
}
/* Now the "ex_data" support */
int ENGINE_set_ex_data(ENGINE *e, int idx, void *arg)
{
return CRYPTO_set_ex_data(&e->ex_data, idx, arg);
}
void *ENGINE_get_ex_data(const ENGINE *e, int idx)
{
return CRYPTO_get_ex_data(&e->ex_data, idx);
}
/*
* Functions to get/set an ENGINE's elements - mainly to avoid exposing the
* ENGINE structure itself.
*/
int ENGINE_set_id(ENGINE *e, const char *id)
{
if (id == NULL) {
ENGINEerr(ENGINE_F_ENGINE_SET_ID, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
e->id = id;
return 1;
}
int ENGINE_set_name(ENGINE *e, const char *name)
{
if (name == NULL) {
ENGINEerr(ENGINE_F_ENGINE_SET_NAME, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
e->name = name;
return 1;
}
int ENGINE_set_destroy_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR destroy_f)
{
e->destroy = destroy_f;
return 1;
}
int ENGINE_set_init_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR init_f)
{
e->init = init_f;
return 1;
}
int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f)
{
e->finish = finish_f;
return 1;
}
int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f)
{
e->ctrl = ctrl_f;
return 1;
}
int ENGINE_set_flags(ENGINE *e, int flags)
{
e->flags = flags;
return 1;
}
int ENGINE_set_cmd_defns(ENGINE *e, const ENGINE_CMD_DEFN *defns)
{
e->cmd_defns = defns;
return 1;
}
const char *ENGINE_get_id(const ENGINE *e)
{
return e->id;
}
const char *ENGINE_get_name(const ENGINE *e)
{
return e->name;
}
ENGINE_GEN_INT_FUNC_PTR ENGINE_get_destroy_function(const ENGINE *e)
{
return e->destroy;
}
ENGINE_GEN_INT_FUNC_PTR ENGINE_get_init_function(const ENGINE *e)
{
return e->init;
}
ENGINE_GEN_INT_FUNC_PTR ENGINE_get_finish_function(const ENGINE *e)
{
return e->finish;
}
ENGINE_CTRL_FUNC_PTR ENGINE_get_ctrl_function(const ENGINE *e)
{
return e->ctrl;
}
int ENGINE_get_flags(const ENGINE *e)
{
return e->flags;
}
const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *e)
{
return e->cmd_defns;
}
/*
* eng_lib.o is pretty much linked into anything that touches ENGINE already,
* so put the "static_state" hack here.
*/
static int internal_static_hack = 0;
void *ENGINE_get_static_state(void)
{
return &internal_static_hack;
}

View file

@ -0,0 +1,349 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
*
* Licensed under the OpenSSL license (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 "eng_int.h"
/*
* The linked-list of pointers to engine types. engine_list_head incorporates
* an implicit structural reference but engine_list_tail does not - the
* latter is a computational optimization and only points to something that
* is already pointed to by its predecessor in the list (or engine_list_head
* itself). In the same way, the use of the "prev" pointer in each ENGINE is
* to save excessive list iteration, it doesn't correspond to an extra
* structural reference. Hence, engine_list_head, and each non-null "next"
* pointer account for the list itself assuming exactly 1 structural
* reference on each list member.
*/
static ENGINE *engine_list_head = NULL;
static ENGINE *engine_list_tail = NULL;
/*
* This cleanup function is only needed internally. If it should be called,
* we register it with the "engine_cleanup_int()" stack to be called during
* cleanup.
*/
static void engine_list_cleanup(void)
{
ENGINE *iterator = engine_list_head;
while (iterator != NULL) {
ENGINE_remove(iterator);
iterator = engine_list_head;
}
return;
}
/*
* These static functions starting with a lower case "engine_" always take
* place when global_engine_lock has been locked up.
*/
static int engine_list_add(ENGINE *e)
{
int conflict = 0;
ENGINE *iterator = NULL;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
iterator = engine_list_head;
while (iterator && !conflict) {
conflict = (strcmp(iterator->id, e->id) == 0);
iterator = iterator->next;
}
if (conflict) {
ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_CONFLICTING_ENGINE_ID);
return 0;
}
if (engine_list_head == NULL) {
/* We are adding to an empty list. */
if (engine_list_tail) {
ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_INTERNAL_LIST_ERROR);
return 0;
}
engine_list_head = e;
e->prev = NULL;
/*
* The first time the list allocates, we should register the cleanup.
*/
engine_cleanup_add_last(engine_list_cleanup);
} else {
/* We are adding to the tail of an existing list. */
if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) {
ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_INTERNAL_LIST_ERROR);
return 0;
}
engine_list_tail->next = e;
e->prev = engine_list_tail;
}
/*
* Having the engine in the list assumes a structural reference.
*/
e->struct_ref++;
engine_ref_debug(e, 0, 1);
/* However it came to be, e is the last item in the list. */
engine_list_tail = e;
e->next = NULL;
return 1;
}
static int engine_list_remove(ENGINE *e)
{
ENGINE *iterator;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
/* We need to check that e is in our linked list! */
iterator = engine_list_head;
while (iterator && (iterator != e))
iterator = iterator->next;
if (iterator == NULL) {
ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
ENGINE_R_ENGINE_IS_NOT_IN_LIST);
return 0;
}
/* un-link e from the chain. */
if (e->next)
e->next->prev = e->prev;
if (e->prev)
e->prev->next = e->next;
/* Correct our head/tail if necessary. */
if (engine_list_head == e)
engine_list_head = e->next;
if (engine_list_tail == e)
engine_list_tail = e->prev;
engine_free_util(e, 0);
return 1;
}
/* Get the first/last "ENGINE" type available. */
ENGINE *ENGINE_get_first(void)
{
ENGINE *ret;
if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
ENGINEerr(ENGINE_F_ENGINE_GET_FIRST, ERR_R_MALLOC_FAILURE);
return NULL;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
ret = engine_list_head;
if (ret) {
ret->struct_ref++;
engine_ref_debug(ret, 0, 1);
}
CRYPTO_THREAD_unlock(global_engine_lock);
return ret;
}
ENGINE *ENGINE_get_last(void)
{
ENGINE *ret;
if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
ENGINEerr(ENGINE_F_ENGINE_GET_LAST, ERR_R_MALLOC_FAILURE);
return NULL;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
ret = engine_list_tail;
if (ret) {
ret->struct_ref++;
engine_ref_debug(ret, 0, 1);
}
CRYPTO_THREAD_unlock(global_engine_lock);
return ret;
}
/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
ENGINE *ENGINE_get_next(ENGINE *e)
{
ENGINE *ret = NULL;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_GET_NEXT, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
ret = e->next;
if (ret) {
/* Return a valid structural reference to the next ENGINE */
ret->struct_ref++;
engine_ref_debug(ret, 0, 1);
}
CRYPTO_THREAD_unlock(global_engine_lock);
/* Release the structural reference to the previous ENGINE */
ENGINE_free(e);
return ret;
}
ENGINE *ENGINE_get_prev(ENGINE *e)
{
ENGINE *ret = NULL;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_GET_PREV, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
ret = e->prev;
if (ret) {
/* Return a valid structural reference to the next ENGINE */
ret->struct_ref++;
engine_ref_debug(ret, 0, 1);
}
CRYPTO_THREAD_unlock(global_engine_lock);
/* Release the structural reference to the previous ENGINE */
ENGINE_free(e);
return ret;
}
/* Add another "ENGINE" type into the list. */
int ENGINE_add(ENGINE *e)
{
int to_return = 1;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_ADD, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if ((e->id == NULL) || (e->name == NULL)) {
ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_ID_OR_NAME_MISSING);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
if (!engine_list_add(e)) {
ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_INTERNAL_LIST_ERROR);
to_return = 0;
}
CRYPTO_THREAD_unlock(global_engine_lock);
return to_return;
}
/* Remove an existing "ENGINE" type from the array. */
int ENGINE_remove(ENGINE *e)
{
int to_return = 1;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_REMOVE, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
if (!engine_list_remove(e)) {
ENGINEerr(ENGINE_F_ENGINE_REMOVE, ENGINE_R_INTERNAL_LIST_ERROR);
to_return = 0;
}
CRYPTO_THREAD_unlock(global_engine_lock);
return to_return;
}
static void engine_cpy(ENGINE *dest, const ENGINE *src)
{
dest->id = src->id;
dest->name = src->name;
#ifndef OPENSSL_NO_RSA
dest->rsa_meth = src->rsa_meth;
#endif
#ifndef OPENSSL_NO_DSA
dest->dsa_meth = src->dsa_meth;
#endif
#ifndef OPENSSL_NO_DH
dest->dh_meth = src->dh_meth;
#endif
#ifndef OPENSSL_NO_EC
dest->ec_meth = src->ec_meth;
#endif
dest->rand_meth = src->rand_meth;
dest->ciphers = src->ciphers;
dest->digests = src->digests;
dest->pkey_meths = src->pkey_meths;
dest->destroy = src->destroy;
dest->init = src->init;
dest->finish = src->finish;
dest->ctrl = src->ctrl;
dest->load_privkey = src->load_privkey;
dest->load_pubkey = src->load_pubkey;
dest->cmd_defns = src->cmd_defns;
dest->flags = src->flags;
}
ENGINE *ENGINE_by_id(const char *id)
{
ENGINE *iterator;
char *load_dir = NULL;
if (id == NULL) {
ENGINEerr(ENGINE_F_ENGINE_BY_ID, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
ENGINEerr(ENGINE_F_ENGINE_BY_ID, ERR_R_MALLOC_FAILURE);
return NULL;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
iterator = engine_list_head;
while (iterator && (strcmp(id, iterator->id) != 0))
iterator = iterator->next;
if (iterator != NULL) {
/*
* We need to return a structural reference. If this is an ENGINE
* type that returns copies, make a duplicate - otherwise increment
* the existing ENGINE's reference count.
*/
if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
ENGINE *cp = ENGINE_new();
if (cp == NULL)
iterator = NULL;
else {
engine_cpy(cp, iterator);
iterator = cp;
}
} else {
iterator->struct_ref++;
engine_ref_debug(iterator, 0, 1);
}
}
CRYPTO_THREAD_unlock(global_engine_lock);
if (iterator != NULL)
return iterator;
/*
* Prevent infinite recursion if we're looking for the dynamic engine.
*/
if (strcmp(id, "dynamic")) {
if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL)
load_dir = ENGINESDIR;
iterator = ENGINE_by_id("dynamic");
if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
!ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
!ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
load_dir, 0) ||
!ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
!ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
goto notfound;
return iterator;
}
notfound:
ENGINE_free(iterator);
ENGINEerr(ENGINE_F_ENGINE_BY_ID, ENGINE_R_NO_SUCH_ENGINE);
ERR_add_error_data(2, "id=", id);
return NULL;
/* EEK! Experimental code ends */
}
int ENGINE_up_ref(ENGINE *e)
{
int i;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_UP_REF(&e->struct_ref, &i, global_engine_lock);
return 1;
}

View file

@ -0,0 +1,648 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
*
* Licensed under the OpenSSL license (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 <stdio.h>
#include <openssl/crypto.h>
#include "internal/cryptlib.h"
#include "internal/engine.h"
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include <openssl/x509v3.h>
/*
* This testing gunk is implemented (and explained) lower down. It also
* assumes the application explicitly calls "ENGINE_load_openssl()" because
* this is no longer automatic in ENGINE_load_builtin_engines().
*/
#define TEST_ENG_OPENSSL_RC4
#ifndef OPENSSL_NO_STDIO
#define TEST_ENG_OPENSSL_PKEY
#endif
/* #define TEST_ENG_OPENSSL_HMAC */
/* #define TEST_ENG_OPENSSL_HMAC_INIT */
/* #define TEST_ENG_OPENSSL_RC4_OTHERS */
#define TEST_ENG_OPENSSL_RC4_P_INIT
/* #define TEST_ENG_OPENSSL_RC4_P_CIPHER */
#define TEST_ENG_OPENSSL_SHA
/* #define TEST_ENG_OPENSSL_SHA_OTHERS */
/* #define TEST_ENG_OPENSSL_SHA_P_INIT */
/* #define TEST_ENG_OPENSSL_SHA_P_UPDATE */
/* #define TEST_ENG_OPENSSL_SHA_P_FINAL */
/* Now check what of those algorithms are actually enabled */
#ifdef OPENSSL_NO_RC4
# undef TEST_ENG_OPENSSL_RC4
# undef TEST_ENG_OPENSSL_RC4_OTHERS
# undef TEST_ENG_OPENSSL_RC4_P_INIT
# undef TEST_ENG_OPENSSL_RC4_P_CIPHER
#endif
static int openssl_destroy(ENGINE *e);
#ifdef TEST_ENG_OPENSSL_RC4
static int openssl_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
const int **nids, int nid);
#endif
#ifdef TEST_ENG_OPENSSL_SHA
static int openssl_digests(ENGINE *e, const EVP_MD **digest,
const int **nids, int nid);
#endif
#ifdef TEST_ENG_OPENSSL_PKEY
static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id,
UI_METHOD *ui_method,
void *callback_data);
#endif
#ifdef TEST_ENG_OPENSSL_HMAC
static int ossl_register_hmac_meth(void);
static int ossl_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
const int **nids, int nid);
#endif
/* The constants used when creating the ENGINE */
static const char *engine_openssl_id = "openssl";
static const char *engine_openssl_name = "Software engine support";
/*
* This internal function is used by ENGINE_openssl() and possibly by the
* "dynamic" ENGINE support too
*/
static int bind_helper(ENGINE *e)
{
if (!ENGINE_set_id(e, engine_openssl_id)
|| !ENGINE_set_name(e, engine_openssl_name)
|| !ENGINE_set_destroy_function(e, openssl_destroy)
#ifndef TEST_ENG_OPENSSL_NO_ALGORITHMS
# ifndef OPENSSL_NO_RSA
|| !ENGINE_set_RSA(e, RSA_get_default_method())
# endif
# ifndef OPENSSL_NO_DSA
|| !ENGINE_set_DSA(e, DSA_get_default_method())
# endif
# ifndef OPENSSL_NO_EC
|| !ENGINE_set_EC(e, EC_KEY_OpenSSL())
# endif
# ifndef OPENSSL_NO_DH
|| !ENGINE_set_DH(e, DH_get_default_method())
# endif
|| !ENGINE_set_RAND(e, RAND_OpenSSL())
# ifdef TEST_ENG_OPENSSL_RC4
|| !ENGINE_set_ciphers(e, openssl_ciphers)
# endif
# ifdef TEST_ENG_OPENSSL_SHA
|| !ENGINE_set_digests(e, openssl_digests)
# endif
#endif
#ifdef TEST_ENG_OPENSSL_PKEY
|| !ENGINE_set_load_privkey_function(e, openssl_load_privkey)
#endif
#ifdef TEST_ENG_OPENSSL_HMAC
|| !ossl_register_hmac_meth()
|| !ENGINE_set_pkey_meths(e, ossl_pkey_meths)
#endif
)
return 0;
/*
* If we add errors to this ENGINE, ensure the error handling is setup
* here
*/
/* openssl_load_error_strings(); */
return 1;
}
static ENGINE *engine_openssl(void)
{
ENGINE *ret = ENGINE_new();
if (ret == NULL)
return NULL;
if (!bind_helper(ret)) {
ENGINE_free(ret);
return NULL;
}
return ret;
}
void engine_load_openssl_int(void)
{
ENGINE *toadd = engine_openssl();
if (!toadd)
return;
ENGINE_add(toadd);
/*
* If the "add" worked, it gets a structural reference. So either way, we
* release our just-created reference.
*/
ENGINE_free(toadd);
ERR_clear_error();
}
/*
* This stuff is needed if this ENGINE is being compiled into a
* self-contained shared-library.
*/
#ifdef ENGINE_DYNAMIC_SUPPORT
static int bind_fn(ENGINE *e, const char *id)
{
if (id && (strcmp(id, engine_openssl_id) != 0))
return 0;
if (!bind_helper(e))
return 0;
return 1;
}
IMPLEMENT_DYNAMIC_CHECK_FN()
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
#endif /* ENGINE_DYNAMIC_SUPPORT */
#ifdef TEST_ENG_OPENSSL_RC4
/*-
* This section of code compiles an "alternative implementation" of two modes of
* RC4 into this ENGINE. The result is that EVP_CIPHER operation for "rc4"
* should under normal circumstances go via this support rather than the default
* EVP support. There are other symbols to tweak the testing;
* TEST_ENC_OPENSSL_RC4_OTHERS - print a one line message to stderr each time
* we're asked for a cipher we don't support (should not happen).
* TEST_ENG_OPENSSL_RC4_P_INIT - print a one line message to stderr each time
* the "init_key" handler is called.
* TEST_ENG_OPENSSL_RC4_P_CIPHER - ditto for the "cipher" handler.
*/
# include <openssl/rc4.h>
# define TEST_RC4_KEY_SIZE 16
typedef struct {
unsigned char key[TEST_RC4_KEY_SIZE];
RC4_KEY ks;
} TEST_RC4_KEY;
# define test(ctx) ((TEST_RC4_KEY *)EVP_CIPHER_CTX_get_cipher_data(ctx))
static int test_rc4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
# ifdef TEST_ENG_OPENSSL_RC4_P_INIT
fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) test_init_key() called\n");
# endif
memcpy(&test(ctx)->key[0], key, EVP_CIPHER_CTX_key_length(ctx));
RC4_set_key(&test(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx),
test(ctx)->key);
return 1;
}
static int test_rc4_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
# ifdef TEST_ENG_OPENSSL_RC4_P_CIPHER
fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) test_cipher() called\n");
# endif
RC4(&test(ctx)->ks, inl, in, out);
return 1;
}
static EVP_CIPHER *r4_cipher = NULL;
static const EVP_CIPHER *test_r4_cipher(void)
{
if (r4_cipher == NULL) {
EVP_CIPHER *cipher;
if ((cipher = EVP_CIPHER_meth_new(NID_rc4, 1, TEST_RC4_KEY_SIZE)) == NULL
|| !EVP_CIPHER_meth_set_iv_length(cipher, 0)
|| !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_VARIABLE_LENGTH)
|| !EVP_CIPHER_meth_set_init(cipher, test_rc4_init_key)
|| !EVP_CIPHER_meth_set_do_cipher(cipher, test_rc4_cipher)
|| !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(TEST_RC4_KEY))) {
EVP_CIPHER_meth_free(cipher);
cipher = NULL;
}
r4_cipher = cipher;
}
return r4_cipher;
}
static void test_r4_cipher_destroy(void)
{
EVP_CIPHER_meth_free(r4_cipher);
r4_cipher = NULL;
}
static EVP_CIPHER *r4_40_cipher = NULL;
static const EVP_CIPHER *test_r4_40_cipher(void)
{
if (r4_40_cipher == NULL) {
EVP_CIPHER *cipher;
if ((cipher = EVP_CIPHER_meth_new(NID_rc4, 1, 5 /* 40 bits */)) == NULL
|| !EVP_CIPHER_meth_set_iv_length(cipher, 0)
|| !EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_VARIABLE_LENGTH)
|| !EVP_CIPHER_meth_set_init(cipher, test_rc4_init_key)
|| !EVP_CIPHER_meth_set_do_cipher(cipher, test_rc4_cipher)
|| !EVP_CIPHER_meth_set_impl_ctx_size(cipher, sizeof(TEST_RC4_KEY))) {
EVP_CIPHER_meth_free(cipher);
cipher = NULL;
}
r4_40_cipher = cipher;
}
return r4_40_cipher;
}
static void test_r4_40_cipher_destroy(void)
{
EVP_CIPHER_meth_free(r4_40_cipher);
r4_40_cipher = NULL;
}
static int test_cipher_nids(const int **nids)
{
static int cipher_nids[4] = { 0, 0, 0, 0 };
static int pos = 0;
static int init = 0;
if (!init) {
const EVP_CIPHER *cipher;
if ((cipher = test_r4_cipher()) != NULL)
cipher_nids[pos++] = EVP_CIPHER_nid(cipher);
if ((cipher = test_r4_40_cipher()) != NULL)
cipher_nids[pos++] = EVP_CIPHER_nid(cipher);
cipher_nids[pos] = 0;
init = 1;
}
*nids = cipher_nids;
return pos;
}
static int openssl_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
const int **nids, int nid)
{
if (!cipher) {
/* We are returning a list of supported nids */
return test_cipher_nids(nids);
}
/* We are being asked for a specific cipher */
if (nid == NID_rc4)
*cipher = test_r4_cipher();
else if (nid == NID_rc4_40)
*cipher = test_r4_40_cipher();
else {
# ifdef TEST_ENG_OPENSSL_RC4_OTHERS
fprintf(stderr, "(TEST_ENG_OPENSSL_RC4) returning NULL for "
"nid %d\n", nid);
# endif
*cipher = NULL;
return 0;
}
return 1;
}
#endif
#ifdef TEST_ENG_OPENSSL_SHA
/* Much the same sort of comment as for TEST_ENG_OPENSSL_RC4 */
# include <openssl/sha.h>
static int test_sha1_init(EVP_MD_CTX *ctx)
{
# ifdef TEST_ENG_OPENSSL_SHA_P_INIT
fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_init() called\n");
# endif
return SHA1_Init(EVP_MD_CTX_md_data(ctx));
}
static int test_sha1_update(EVP_MD_CTX *ctx, const void *data, size_t count)
{
# ifdef TEST_ENG_OPENSSL_SHA_P_UPDATE
fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_update() called\n");
# endif
return SHA1_Update(EVP_MD_CTX_md_data(ctx), data, count);
}
static int test_sha1_final(EVP_MD_CTX *ctx, unsigned char *md)
{
# ifdef TEST_ENG_OPENSSL_SHA_P_FINAL
fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) test_sha1_final() called\n");
# endif
return SHA1_Final(md, EVP_MD_CTX_md_data(ctx));
}
static EVP_MD *sha1_md = NULL;
static const EVP_MD *test_sha_md(void)
{
if (sha1_md == NULL) {
EVP_MD *md;
if ((md = EVP_MD_meth_new(NID_sha1, NID_sha1WithRSAEncryption)) == NULL
|| !EVP_MD_meth_set_result_size(md, SHA_DIGEST_LENGTH)
|| !EVP_MD_meth_set_input_blocksize(md, SHA_CBLOCK)
|| !EVP_MD_meth_set_app_datasize(md,
sizeof(EVP_MD *) + sizeof(SHA_CTX))
|| !EVP_MD_meth_set_flags(md, 0)
|| !EVP_MD_meth_set_init(md, test_sha1_init)
|| !EVP_MD_meth_set_update(md, test_sha1_update)
|| !EVP_MD_meth_set_final(md, test_sha1_final)) {
EVP_MD_meth_free(md);
md = NULL;
}
sha1_md = md;
}
return sha1_md;
}
static void test_sha_md_destroy(void)
{
EVP_MD_meth_free(sha1_md);
sha1_md = NULL;
}
static int test_digest_nids(const int **nids)
{
static int digest_nids[2] = { 0, 0 };
static int pos = 0;
static int init = 0;
if (!init) {
const EVP_MD *md;
if ((md = test_sha_md()) != NULL)
digest_nids[pos++] = EVP_MD_type(md);
digest_nids[pos] = 0;
init = 1;
}
*nids = digest_nids;
return pos;
}
static int openssl_digests(ENGINE *e, const EVP_MD **digest,
const int **nids, int nid)
{
if (!digest) {
/* We are returning a list of supported nids */
return test_digest_nids(nids);
}
/* We are being asked for a specific digest */
if (nid == NID_sha1)
*digest = test_sha_md();
else {
# ifdef TEST_ENG_OPENSSL_SHA_OTHERS
fprintf(stderr, "(TEST_ENG_OPENSSL_SHA) returning NULL for "
"nid %d\n", nid);
# endif
*digest = NULL;
return 0;
}
return 1;
}
#endif
#ifdef TEST_ENG_OPENSSL_PKEY
static EVP_PKEY *openssl_load_privkey(ENGINE *eng, const char *key_id,
UI_METHOD *ui_method,
void *callback_data)
{
BIO *in;
EVP_PKEY *key;
fprintf(stderr, "(TEST_ENG_OPENSSL_PKEY)Loading Private key %s\n",
key_id);
in = BIO_new_file(key_id, "r");
if (!in)
return NULL;
key = PEM_read_bio_PrivateKey(in, NULL, 0, NULL);
BIO_free(in);
return key;
}
#endif
#ifdef TEST_ENG_OPENSSL_HMAC
/*
* Experimental HMAC redirection implementation: mainly copied from
* hm_pmeth.c
*/
/* HMAC pkey context structure */
typedef struct {
const EVP_MD *md; /* MD for HMAC use */
ASN1_OCTET_STRING ktmp; /* Temp storage for key */
HMAC_CTX *ctx;
} OSSL_HMAC_PKEY_CTX;
static int ossl_hmac_init(EVP_PKEY_CTX *ctx)
{
OSSL_HMAC_PKEY_CTX *hctx;
if ((hctx = OPENSSL_zalloc(sizeof(*hctx))) == NULL) {
ENGINEerr(ENGINE_F_OSSL_HMAC_INIT, ERR_R_MALLOC_FAILURE);
return 0;
}
hctx->ktmp.type = V_ASN1_OCTET_STRING;
hctx->ctx = HMAC_CTX_new();
if (hctx->ctx == NULL) {
OPENSSL_free(hctx);
return 0;
}
EVP_PKEY_CTX_set_data(ctx, hctx);
EVP_PKEY_CTX_set0_keygen_info(ctx, NULL, 0);
# ifdef TEST_ENG_OPENSSL_HMAC_INIT
fprintf(stderr, "(TEST_ENG_OPENSSL_HMAC) ossl_hmac_init() called\n");
# endif
return 1;
}
static void ossl_hmac_cleanup(EVP_PKEY_CTX *ctx);
static int ossl_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
{
OSSL_HMAC_PKEY_CTX *sctx, *dctx;
/* allocate memory for dst->data and a new HMAC_CTX in dst->data->ctx */
if (!ossl_hmac_init(dst))
return 0;
sctx = EVP_PKEY_CTX_get_data(src);
dctx = EVP_PKEY_CTX_get_data(dst);
dctx->md = sctx->md;
if (!HMAC_CTX_copy(dctx->ctx, sctx->ctx))
goto err;
if (sctx->ktmp.data) {
if (!ASN1_OCTET_STRING_set(&dctx->ktmp,
sctx->ktmp.data, sctx->ktmp.length))
goto err;
}
return 1;
err:
/* release HMAC_CTX in dst->data->ctx and memory allocated for dst->data */
ossl_hmac_cleanup(dst);
return 0;
}
static void ossl_hmac_cleanup(EVP_PKEY_CTX *ctx)
{
OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
if (hctx) {
HMAC_CTX_free(hctx->ctx);
OPENSSL_clear_free(hctx->ktmp.data, hctx->ktmp.length);
OPENSSL_free(hctx);
EVP_PKEY_CTX_set_data(ctx, NULL);
}
}
static int ossl_hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
{
ASN1_OCTET_STRING *hkey = NULL;
OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
if (!hctx->ktmp.data)
return 0;
hkey = ASN1_OCTET_STRING_dup(&hctx->ktmp);
if (!hkey)
return 0;
EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hkey);
return 1;
}
static int ossl_int_update(EVP_MD_CTX *ctx, const void *data, size_t count)
{
OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(EVP_MD_CTX_pkey_ctx(ctx));
if (!HMAC_Update(hctx->ctx, data, count))
return 0;
return 1;
}
static int ossl_hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
{
EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
EVP_MD_CTX_set_update_fn(mctx, ossl_int_update);
return 1;
}
static int ossl_hmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig,
size_t *siglen, EVP_MD_CTX *mctx)
{
unsigned int hlen;
OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
int l = EVP_MD_CTX_size(mctx);
if (l < 0)
return 0;
*siglen = l;
if (!sig)
return 1;
if (!HMAC_Final(hctx->ctx, sig, &hlen))
return 0;
*siglen = (size_t)hlen;
return 1;
}
static int ossl_hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
{
OSSL_HMAC_PKEY_CTX *hctx = EVP_PKEY_CTX_get_data(ctx);
EVP_PKEY *pk;
ASN1_OCTET_STRING *key;
switch (type) {
case EVP_PKEY_CTRL_SET_MAC_KEY:
if ((!p2 && p1 > 0) || (p1 < -1))
return 0;
if (!ASN1_OCTET_STRING_set(&hctx->ktmp, p2, p1))
return 0;
break;
case EVP_PKEY_CTRL_MD:
hctx->md = p2;
break;
case EVP_PKEY_CTRL_DIGESTINIT:
pk = EVP_PKEY_CTX_get0_pkey(ctx);
key = EVP_PKEY_get0(pk);
if (!HMAC_Init_ex(hctx->ctx, key->data, key->length, hctx->md, NULL))
return 0;
break;
default:
return -2;
}
return 1;
}
static int ossl_hmac_ctrl_str(EVP_PKEY_CTX *ctx,
const char *type, const char *value)
{
if (!value) {
return 0;
}
if (strcmp(type, "key") == 0) {
void *p = (void *)value;
return ossl_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, -1, p);
}
if (strcmp(type, "hexkey") == 0) {
unsigned char *key;
int r;
long keylen;
key = OPENSSL_hexstr2buf(value, &keylen);
if (!key)
return 0;
r = ossl_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, keylen, key);
OPENSSL_free(key);
return r;
}
return -2;
}
static EVP_PKEY_METHOD *ossl_hmac_meth;
static int ossl_register_hmac_meth(void)
{
EVP_PKEY_METHOD *meth;
meth = EVP_PKEY_meth_new(EVP_PKEY_HMAC, 0);
if (meth == NULL)
return 0;
EVP_PKEY_meth_set_init(meth, ossl_hmac_init);
EVP_PKEY_meth_set_copy(meth, ossl_hmac_copy);
EVP_PKEY_meth_set_cleanup(meth, ossl_hmac_cleanup);
EVP_PKEY_meth_set_keygen(meth, 0, ossl_hmac_keygen);
EVP_PKEY_meth_set_signctx(meth, ossl_hmac_signctx_init,
ossl_hmac_signctx);
EVP_PKEY_meth_set_ctrl(meth, ossl_hmac_ctrl, ossl_hmac_ctrl_str);
ossl_hmac_meth = meth;
return 1;
}
static int ossl_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
const int **nids, int nid)
{
static int ossl_pkey_nids[] = {
EVP_PKEY_HMAC,
0
};
if (!pmeth) {
*nids = ossl_pkey_nids;
return 1;
}
if (nid == EVP_PKEY_HMAC) {
*pmeth = ossl_hmac_meth;
return 1;
}
*pmeth = NULL;
return 0;
}
#endif
int openssl_destroy(ENGINE *e)
{
test_sha_md_destroy();
#ifdef TEST_ENG_OPENSSL_RC4
test_r4_cipher_destroy();
test_r4_40_cipher_destroy();
#endif
return 1;
}

View file

@ -0,0 +1,140 @@
/*
* Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
/* Basic get/set stuff */
int ENGINE_set_load_privkey_function(ENGINE *e,
ENGINE_LOAD_KEY_PTR loadpriv_f)
{
e->load_privkey = loadpriv_f;
return 1;
}
int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f)
{
e->load_pubkey = loadpub_f;
return 1;
}
int ENGINE_set_load_ssl_client_cert_function(ENGINE *e,
ENGINE_SSL_CLIENT_CERT_PTR
loadssl_f)
{
e->load_ssl_client_cert = loadssl_f;
return 1;
}
ENGINE_LOAD_KEY_PTR ENGINE_get_load_privkey_function(const ENGINE *e)
{
return e->load_privkey;
}
ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e)
{
return e->load_pubkey;
}
ENGINE_SSL_CLIENT_CERT_PTR ENGINE_get_ssl_client_cert_function(const ENGINE
*e)
{
return e->load_ssl_client_cert;
}
/* API functions to load public/private keys */
EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
UI_METHOD *ui_method, void *callback_data)
{
EVP_PKEY *pkey;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY,
ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
if (e->funct_ref == 0) {
CRYPTO_THREAD_unlock(global_engine_lock);
ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY, ENGINE_R_NOT_INITIALISED);
return 0;
}
CRYPTO_THREAD_unlock(global_engine_lock);
if (!e->load_privkey) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY,
ENGINE_R_NO_LOAD_FUNCTION);
return 0;
}
pkey = e->load_privkey(e, key_id, ui_method, callback_data);
if (!pkey) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_PRIVATE_KEY,
ENGINE_R_FAILED_LOADING_PRIVATE_KEY);
return 0;
}
return pkey;
}
EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
UI_METHOD *ui_method, void *callback_data)
{
EVP_PKEY *pkey;
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY,
ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
if (e->funct_ref == 0) {
CRYPTO_THREAD_unlock(global_engine_lock);
ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY, ENGINE_R_NOT_INITIALISED);
return 0;
}
CRYPTO_THREAD_unlock(global_engine_lock);
if (!e->load_pubkey) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY, ENGINE_R_NO_LOAD_FUNCTION);
return 0;
}
pkey = e->load_pubkey(e, key_id, ui_method, callback_data);
if (!pkey) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_PUBLIC_KEY,
ENGINE_R_FAILED_LOADING_PUBLIC_KEY);
return 0;
}
return pkey;
}
int ENGINE_load_ssl_client_cert(ENGINE *e, SSL *s,
STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
EVP_PKEY **ppkey, STACK_OF(X509) **pother,
UI_METHOD *ui_method, void *callback_data)
{
if (e == NULL) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT,
ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
if (e->funct_ref == 0) {
CRYPTO_THREAD_unlock(global_engine_lock);
ENGINEerr(ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT,
ENGINE_R_NOT_INITIALISED);
return 0;
}
CRYPTO_THREAD_unlock(global_engine_lock);
if (!e->load_ssl_client_cert) {
ENGINEerr(ENGINE_F_ENGINE_LOAD_SSL_CLIENT_CERT,
ENGINE_R_NO_LOAD_FUNCTION);
return 0;
}
return e->load_ssl_client_cert(e, s, ca_dn, pcert, ppkey, pother,
ui_method, callback_data);
}

View file

@ -0,0 +1,97 @@
/*
* Copyright 2011-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 <openssl/opensslconf.h>
#include <stdio.h>
#include <string.h>
#include "internal/engine.h"
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/crypto.h>
#if (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64) || defined(__x86_64__) || \
defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ)
size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len);
static int get_random_bytes(unsigned char *buf, int num)
{
if (num < 0) {
return 0;
}
return (size_t)num == OPENSSL_ia32_rdrand_bytes(buf, (size_t)num);
}
static int random_status(void)
{
return 1;
}
static RAND_METHOD rdrand_meth = {
NULL, /* seed */
get_random_bytes,
NULL, /* cleanup */
NULL, /* add */
get_random_bytes,
random_status,
};
static int rdrand_init(ENGINE *e)
{
return 1;
}
static const char *engine_e_rdrand_id = "rdrand";
static const char *engine_e_rdrand_name = "Intel RDRAND engine";
static int bind_helper(ENGINE *e)
{
if (!ENGINE_set_id(e, engine_e_rdrand_id) ||
!ENGINE_set_name(e, engine_e_rdrand_name) ||
!ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) ||
!ENGINE_set_init_function(e, rdrand_init) ||
!ENGINE_set_RAND(e, &rdrand_meth))
return 0;
return 1;
}
static ENGINE *ENGINE_rdrand(void)
{
ENGINE *ret = ENGINE_new();
if (ret == NULL)
return NULL;
if (!bind_helper(ret)) {
ENGINE_free(ret);
return NULL;
}
return ret;
}
void engine_load_rdrand_int(void)
{
extern unsigned int OPENSSL_ia32cap_P[];
if (OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) {
ENGINE *toadd = ENGINE_rdrand();
if (!toadd)
return;
ENGINE_add(toadd);
ENGINE_free(toadd);
ERR_clear_error();
}
}
#else
void engine_load_rdrand_int(void)
{
}
#endif

View file

@ -0,0 +1,308 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "internal/cryptlib.h"
#include <openssl/evp.h>
#include <openssl/lhash.h>
#include "eng_int.h"
/* The type of the items in the table */
struct st_engine_pile {
/* The 'nid' of this algorithm/mode */
int nid;
/* ENGINEs that implement this algorithm/mode. */
STACK_OF(ENGINE) *sk;
/* The default ENGINE to perform this algorithm/mode. */
ENGINE *funct;
/*
* Zero if 'sk' is newer than the cached 'funct', non-zero otherwise
*/
int uptodate;
};
/* The type exposed in eng_int.h */
struct st_engine_table {
LHASH_OF(ENGINE_PILE) piles;
}; /* ENGINE_TABLE */
typedef struct st_engine_pile_doall {
engine_table_doall_cb *cb;
void *arg;
} ENGINE_PILE_DOALL;
/* Global flags (ENGINE_TABLE_FLAG_***). */
static unsigned int table_flags = 0;
/* API function manipulating 'table_flags' */
unsigned int ENGINE_get_table_flags(void)
{
return table_flags;
}
void ENGINE_set_table_flags(unsigned int flags)
{
table_flags = flags;
}
/* Internal functions for the "piles" hash table */
static unsigned long engine_pile_hash(const ENGINE_PILE *c)
{
return c->nid;
}
static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
{
return a->nid - b->nid;
}
static int int_table_check(ENGINE_TABLE **t, int create)
{
LHASH_OF(ENGINE_PILE) *lh;
if (*t)
return 1;
if (!create)
return 0;
if ((lh = lh_ENGINE_PILE_new(engine_pile_hash, engine_pile_cmp)) == NULL)
return 0;
*t = (ENGINE_TABLE *)lh;
return 1;
}
/*
* Privately exposed (via eng_int.h) functions for adding and/or removing
* ENGINEs from the implementation table
*/
int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
ENGINE *e, const int *nids, int num_nids,
int setdefault)
{
int ret = 0, added = 0;
ENGINE_PILE tmplate, *fnd;
CRYPTO_THREAD_write_lock(global_engine_lock);
if (!(*table))
added = 1;
if (!int_table_check(table, 1))
goto end;
if (added)
/* The cleanup callback needs to be added */
engine_cleanup_add_first(cleanup);
while (num_nids--) {
tmplate.nid = *nids;
fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
if (!fnd) {
fnd = OPENSSL_malloc(sizeof(*fnd));
if (fnd == NULL)
goto end;
fnd->uptodate = 1;
fnd->nid = *nids;
fnd->sk = sk_ENGINE_new_null();
if (!fnd->sk) {
OPENSSL_free(fnd);
goto end;
}
fnd->funct = NULL;
(void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd);
if (lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate) != fnd) {
sk_ENGINE_free(fnd->sk);
OPENSSL_free(fnd);
goto end;
}
}
/* A registration shouldn't add duplicate entries */
(void)sk_ENGINE_delete_ptr(fnd->sk, e);
/*
* if 'setdefault', this ENGINE goes to the head of the list
*/
if (!sk_ENGINE_push(fnd->sk, e))
goto end;
/* "touch" this ENGINE_PILE */
fnd->uptodate = 0;
if (setdefault) {
if (!engine_unlocked_init(e)) {
ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
ENGINE_R_INIT_FAILED);
goto end;
}
if (fnd->funct)
engine_unlocked_finish(fnd->funct, 0);
fnd->funct = e;
fnd->uptodate = 1;
}
nids++;
}
ret = 1;
end:
CRYPTO_THREAD_unlock(global_engine_lock);
return ret;
}
static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e)
{
int n;
/* Iterate the 'c->sk' stack removing any occurrence of 'e' */
while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) {
(void)sk_ENGINE_delete(pile->sk, n);
pile->uptodate = 0;
}
if (pile->funct == e) {
engine_unlocked_finish(e, 0);
pile->funct = NULL;
}
}
IMPLEMENT_LHASH_DOALL_ARG(ENGINE_PILE, ENGINE);
void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
{
CRYPTO_THREAD_write_lock(global_engine_lock);
if (int_table_check(table, 0))
lh_ENGINE_PILE_doall_ENGINE(&(*table)->piles, int_unregister_cb, e);
CRYPTO_THREAD_unlock(global_engine_lock);
}
static void int_cleanup_cb_doall(ENGINE_PILE *p)
{
if (!p)
return;
sk_ENGINE_free(p->sk);
if (p->funct)
engine_unlocked_finish(p->funct, 0);
OPENSSL_free(p);
}
void engine_table_cleanup(ENGINE_TABLE **table)
{
CRYPTO_THREAD_write_lock(global_engine_lock);
if (*table) {
lh_ENGINE_PILE_doall(&(*table)->piles, int_cleanup_cb_doall);
lh_ENGINE_PILE_free(&(*table)->piles);
*table = NULL;
}
CRYPTO_THREAD_unlock(global_engine_lock);
}
/* return a functional reference for a given 'nid' */
#ifndef ENGINE_TABLE_DEBUG
ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
#else
ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
int l)
#endif
{
ENGINE *ret = NULL;
ENGINE_PILE tmplate, *fnd = NULL;
int initres, loop = 0;
if (!(*table)) {
#ifdef ENGINE_TABLE_DEBUG
fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
"registered!\n", f, l, nid);
#endif
return NULL;
}
ERR_set_mark();
CRYPTO_THREAD_write_lock(global_engine_lock);
/*
* Check again inside the lock otherwise we could race against cleanup
* operations. But don't worry about a fprintf(stderr).
*/
if (!int_table_check(table, 0))
goto end;
tmplate.nid = nid;
fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
if (!fnd)
goto end;
if (fnd->funct && engine_unlocked_init(fnd->funct)) {
#ifdef ENGINE_TABLE_DEBUG
fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
"ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
#endif
ret = fnd->funct;
goto end;
}
if (fnd->uptodate) {
ret = fnd->funct;
goto end;
}
trynext:
ret = sk_ENGINE_value(fnd->sk, loop++);
if (!ret) {
#ifdef ENGINE_TABLE_DEBUG
fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
"registered implementations would initialise\n", f, l, nid);
#endif
goto end;
}
/* Try to initialise the ENGINE? */
if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
initres = engine_unlocked_init(ret);
else
initres = 0;
if (initres) {
/* Update 'funct' */
if ((fnd->funct != ret) && engine_unlocked_init(ret)) {
/* If there was a previous default we release it. */
if (fnd->funct)
engine_unlocked_finish(fnd->funct, 0);
fnd->funct = ret;
#ifdef ENGINE_TABLE_DEBUG
fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
"setting default to '%s'\n", f, l, nid, ret->id);
#endif
}
#ifdef ENGINE_TABLE_DEBUG
fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
"newly initialised '%s'\n", f, l, nid, ret->id);
#endif
goto end;
}
goto trynext;
end:
/*
* If it failed, it is unlikely to succeed again until some future
* registrations have taken place. In all cases, we cache.
*/
if (fnd)
fnd->uptodate = 1;
#ifdef ENGINE_TABLE_DEBUG
if (ret)
fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
"ENGINE '%s'\n", f, l, nid, ret->id);
else
fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
"'no matching ENGINE'\n", f, l, nid);
#endif
CRYPTO_THREAD_unlock(global_engine_lock);
/*
* Whatever happened, any failed init()s are not failures in this
* context, so clear our error state.
*/
ERR_pop_to_mark();
return ret;
}
/* Table enumeration */
static void int_dall(const ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall)
{
dall->cb(pile->nid, pile->sk, pile->funct, dall->arg);
}
IMPLEMENT_LHASH_DOALL_ARG_CONST(ENGINE_PILE, ENGINE_PILE_DOALL);
void engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb,
void *arg)
{
ENGINE_PILE_DOALL dall;
dall.cb = cb;
dall.arg = arg;
if (table)
lh_ENGINE_PILE_doall_ENGINE_PILE_DOALL(&table->piles, int_dall, &dall);
}

View file

@ -0,0 +1,209 @@
/*
* Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "e_os.h"
#include "eng_int.h"
#include <openssl/evp.h>
#include "internal/asn1_int.h"
/*
* If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the
* function that is used by EVP to hook in pkey_asn1_meth code and cache
* defaults (etc), will display brief debugging summaries to stderr with the
* 'nid'.
*/
/* #define ENGINE_PKEY_ASN1_METH_DEBUG */
static ENGINE_TABLE *pkey_asn1_meth_table = NULL;
void ENGINE_unregister_pkey_asn1_meths(ENGINE *e)
{
engine_table_unregister(&pkey_asn1_meth_table, e);
}
static void engine_unregister_all_pkey_asn1_meths(void)
{
engine_table_cleanup(&pkey_asn1_meth_table);
}
int ENGINE_register_pkey_asn1_meths(ENGINE *e)
{
if (e->pkey_asn1_meths) {
const int *nids;
int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&pkey_asn1_meth_table,
engine_unregister_all_pkey_asn1_meths,
e, nids, num_nids, 0);
}
return 1;
}
void ENGINE_register_all_pkey_asn1_meths(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_pkey_asn1_meths(e);
}
int ENGINE_set_default_pkey_asn1_meths(ENGINE *e)
{
if (e->pkey_asn1_meths) {
const int *nids;
int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&pkey_asn1_meth_table,
engine_unregister_all_pkey_asn1_meths,
e, nids, num_nids, 1);
}
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references) for a given pkey_asn1_meth 'nid'
*/
ENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid)
{
return engine_table_select(&pkey_asn1_meth_table, nid);
}
/*
* Obtains a pkey_asn1_meth implementation from an ENGINE functional
* reference
*/
const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid)
{
EVP_PKEY_ASN1_METHOD *ret;
ENGINE_PKEY_ASN1_METHS_PTR fn = ENGINE_get_pkey_asn1_meths(e);
if (!fn || !fn(e, &ret, NULL, nid)) {
ENGINEerr(ENGINE_F_ENGINE_GET_PKEY_ASN1_METH,
ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD);
return NULL;
}
return ret;
}
/* Gets the pkey_asn1_meth callback from an ENGINE structure */
ENGINE_PKEY_ASN1_METHS_PTR ENGINE_get_pkey_asn1_meths(const ENGINE *e)
{
return e->pkey_asn1_meths;
}
/* Sets the pkey_asn1_meth callback in an ENGINE structure */
int ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f)
{
e->pkey_asn1_meths = f;
return 1;
}
/*
* Internal function to free up EVP_PKEY_ASN1_METHOD structures before an
* ENGINE is destroyed
*/
void engine_pkey_asn1_meths_free(ENGINE *e)
{
int i;
EVP_PKEY_ASN1_METHOD *pkm;
if (e->pkey_asn1_meths) {
const int *pknids;
int npknids;
npknids = e->pkey_asn1_meths(e, NULL, &pknids, 0);
for (i = 0; i < npknids; i++) {
if (e->pkey_asn1_meths(e, &pkm, NULL, pknids[i])) {
EVP_PKEY_asn1_free(pkm);
}
}
}
}
/*
* Find a method based on a string. This does a linear search through all
* implemented algorithms. This is OK in practice because only a small number
* of algorithms are likely to be implemented in an engine and it is not used
* for speed critical operations.
*/
const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e,
const char *str,
int len)
{
int i, nidcount;
const int *nids;
EVP_PKEY_ASN1_METHOD *ameth;
if (!e->pkey_asn1_meths)
return NULL;
if (len == -1)
len = strlen(str);
nidcount = e->pkey_asn1_meths(e, NULL, &nids, 0);
for (i = 0; i < nidcount; i++) {
e->pkey_asn1_meths(e, &ameth, NULL, nids[i]);
if (((int)strlen(ameth->pem_str) == len)
&& strncasecmp(ameth->pem_str, str, len) == 0)
return ameth;
}
return NULL;
}
typedef struct {
ENGINE *e;
const EVP_PKEY_ASN1_METHOD *ameth;
const char *str;
int len;
} ENGINE_FIND_STR;
static void look_str_cb(int nid, STACK_OF(ENGINE) *sk, ENGINE *def, void *arg)
{
ENGINE_FIND_STR *lk = arg;
int i;
if (lk->ameth)
return;
for (i = 0; i < sk_ENGINE_num(sk); i++) {
ENGINE *e = sk_ENGINE_value(sk, i);
EVP_PKEY_ASN1_METHOD *ameth;
e->pkey_asn1_meths(e, &ameth, NULL, nid);
if (ameth != NULL
&& ((int)strlen(ameth->pem_str) == lk->len)
&& strncasecmp(ameth->pem_str, lk->str, lk->len) == 0) {
lk->e = e;
lk->ameth = ameth;
return;
}
}
}
const EVP_PKEY_ASN1_METHOD *ENGINE_pkey_asn1_find_str(ENGINE **pe,
const char *str,
int len)
{
ENGINE_FIND_STR fstr;
fstr.e = NULL;
fstr.ameth = NULL;
fstr.str = str;
fstr.len = len;
if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
ENGINEerr(ENGINE_F_ENGINE_PKEY_ASN1_FIND_STR, ERR_R_MALLOC_FAILURE);
return NULL;
}
CRYPTO_THREAD_write_lock(global_engine_lock);
engine_table_doall(pkey_asn1_meth_table, look_str_cb, &fstr);
/* If found obtain a structural reference to engine */
if (fstr.e) {
fstr.e->struct_ref++;
engine_ref_debug(fstr.e, 0, 1);
}
*pe = fstr.e;
CRYPTO_THREAD_unlock(global_engine_lock);
return fstr.ameth;
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
static ENGINE_TABLE *cipher_table = NULL;
void ENGINE_unregister_ciphers(ENGINE *e)
{
engine_table_unregister(&cipher_table, e);
}
static void engine_unregister_all_ciphers(void)
{
engine_table_cleanup(&cipher_table);
}
int ENGINE_register_ciphers(ENGINE *e)
{
if (e->ciphers) {
const int *nids;
int num_nids = e->ciphers(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&cipher_table,
engine_unregister_all_ciphers, e,
nids, num_nids, 0);
}
return 1;
}
void ENGINE_register_all_ciphers(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_ciphers(e);
}
int ENGINE_set_default_ciphers(ENGINE *e)
{
if (e->ciphers) {
const int *nids;
int num_nids = e->ciphers(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&cipher_table,
engine_unregister_all_ciphers, e,
nids, num_nids, 1);
}
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references) for a given cipher 'nid'
*/
ENGINE *ENGINE_get_cipher_engine(int nid)
{
return engine_table_select(&cipher_table, nid);
}
/* Obtains a cipher implementation from an ENGINE functional reference */
const EVP_CIPHER *ENGINE_get_cipher(ENGINE *e, int nid)
{
const EVP_CIPHER *ret;
ENGINE_CIPHERS_PTR fn = ENGINE_get_ciphers(e);
if (!fn || !fn(e, &ret, NULL, nid)) {
ENGINEerr(ENGINE_F_ENGINE_GET_CIPHER, ENGINE_R_UNIMPLEMENTED_CIPHER);
return NULL;
}
return ret;
}
/* Gets the cipher callback from an ENGINE structure */
ENGINE_CIPHERS_PTR ENGINE_get_ciphers(const ENGINE *e)
{
return e->ciphers;
}
/* Sets the cipher callback in an ENGINE structure */
int ENGINE_set_ciphers(ENGINE *e, ENGINE_CIPHERS_PTR f)
{
e->ciphers = f;
return 1;
}

View file

@ -0,0 +1,72 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
static ENGINE_TABLE *dh_table = NULL;
static const int dummy_nid = 1;
void ENGINE_unregister_DH(ENGINE *e)
{
engine_table_unregister(&dh_table, e);
}
static void engine_unregister_all_DH(void)
{
engine_table_cleanup(&dh_table);
}
int ENGINE_register_DH(ENGINE *e)
{
if (e->dh_meth)
return engine_table_register(&dh_table,
engine_unregister_all_DH, e, &dummy_nid,
1, 0);
return 1;
}
void ENGINE_register_all_DH(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_DH(e);
}
int ENGINE_set_default_DH(ENGINE *e)
{
if (e->dh_meth)
return engine_table_register(&dh_table,
engine_unregister_all_DH, e, &dummy_nid,
1, 1);
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references).
*/
ENGINE *ENGINE_get_default_DH(void)
{
return engine_table_select(&dh_table, dummy_nid);
}
/* Obtains an DH implementation from an ENGINE functional reference */
const DH_METHOD *ENGINE_get_DH(const ENGINE *e)
{
return e->dh_meth;
}
/* Sets an DH implementation in an ENGINE structure */
int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth)
{
e->dh_meth = dh_meth;
return 1;
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
static ENGINE_TABLE *digest_table = NULL;
void ENGINE_unregister_digests(ENGINE *e)
{
engine_table_unregister(&digest_table, e);
}
static void engine_unregister_all_digests(void)
{
engine_table_cleanup(&digest_table);
}
int ENGINE_register_digests(ENGINE *e)
{
if (e->digests) {
const int *nids;
int num_nids = e->digests(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&digest_table,
engine_unregister_all_digests, e,
nids, num_nids, 0);
}
return 1;
}
void ENGINE_register_all_digests(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_digests(e);
}
int ENGINE_set_default_digests(ENGINE *e)
{
if (e->digests) {
const int *nids;
int num_nids = e->digests(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&digest_table,
engine_unregister_all_digests, e,
nids, num_nids, 1);
}
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references) for a given digest 'nid'
*/
ENGINE *ENGINE_get_digest_engine(int nid)
{
return engine_table_select(&digest_table, nid);
}
/* Obtains a digest implementation from an ENGINE functional reference */
const EVP_MD *ENGINE_get_digest(ENGINE *e, int nid)
{
const EVP_MD *ret;
ENGINE_DIGESTS_PTR fn = ENGINE_get_digests(e);
if (!fn || !fn(e, &ret, NULL, nid)) {
ENGINEerr(ENGINE_F_ENGINE_GET_DIGEST, ENGINE_R_UNIMPLEMENTED_DIGEST);
return NULL;
}
return ret;
}
/* Gets the digest callback from an ENGINE structure */
ENGINE_DIGESTS_PTR ENGINE_get_digests(const ENGINE *e)
{
return e->digests;
}
/* Sets the digest callback in an ENGINE structure */
int ENGINE_set_digests(ENGINE *e, ENGINE_DIGESTS_PTR f)
{
e->digests = f;
return 1;
}

View file

@ -0,0 +1,72 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
static ENGINE_TABLE *dsa_table = NULL;
static const int dummy_nid = 1;
void ENGINE_unregister_DSA(ENGINE *e)
{
engine_table_unregister(&dsa_table, e);
}
static void engine_unregister_all_DSA(void)
{
engine_table_cleanup(&dsa_table);
}
int ENGINE_register_DSA(ENGINE *e)
{
if (e->dsa_meth)
return engine_table_register(&dsa_table,
engine_unregister_all_DSA, e, &dummy_nid,
1, 0);
return 1;
}
void ENGINE_register_all_DSA(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_DSA(e);
}
int ENGINE_set_default_DSA(ENGINE *e)
{
if (e->dsa_meth)
return engine_table_register(&dsa_table,
engine_unregister_all_DSA, e, &dummy_nid,
1, 1);
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references).
*/
ENGINE *ENGINE_get_default_DSA(void)
{
return engine_table_select(&dsa_table, dummy_nid);
}
/* Obtains an DSA implementation from an ENGINE functional reference */
const DSA_METHOD *ENGINE_get_DSA(const ENGINE *e)
{
return e->dsa_meth;
}
/* Sets an DSA implementation in an ENGINE structure */
int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth)
{
e->dsa_meth = dsa_meth;
return 1;
}

View file

@ -0,0 +1,72 @@
/*
* Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
static ENGINE_TABLE *dh_table = NULL;
static const int dummy_nid = 1;
void ENGINE_unregister_EC(ENGINE *e)
{
engine_table_unregister(&dh_table, e);
}
static void engine_unregister_all_EC(void)
{
engine_table_cleanup(&dh_table);
}
int ENGINE_register_EC(ENGINE *e)
{
if (e->ec_meth != NULL)
return engine_table_register(&dh_table,
engine_unregister_all_EC, e, &dummy_nid,
1, 0);
return 1;
}
void ENGINE_register_all_EC(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_EC(e);
}
int ENGINE_set_default_EC(ENGINE *e)
{
if (e->ec_meth != NULL)
return engine_table_register(&dh_table,
engine_unregister_all_EC, e, &dummy_nid,
1, 1);
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references).
*/
ENGINE *ENGINE_get_default_EC(void)
{
return engine_table_select(&dh_table, dummy_nid);
}
/* Obtains an EC_KEY implementation from an ENGINE functional reference */
const EC_KEY_METHOD *ENGINE_get_EC(const ENGINE *e)
{
return e->ec_meth;
}
/* Sets an EC_KEY implementation in an ENGINE structure */
int ENGINE_set_EC(ENGINE *e, const EC_KEY_METHOD *ec_meth)
{
e->ec_meth = ec_meth;
return 1;
}

View file

@ -0,0 +1,114 @@
/*
* Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
#include <openssl/evp.h>
static ENGINE_TABLE *pkey_meth_table = NULL;
void ENGINE_unregister_pkey_meths(ENGINE *e)
{
engine_table_unregister(&pkey_meth_table, e);
}
static void engine_unregister_all_pkey_meths(void)
{
engine_table_cleanup(&pkey_meth_table);
}
int ENGINE_register_pkey_meths(ENGINE *e)
{
if (e->pkey_meths) {
const int *nids;
int num_nids = e->pkey_meths(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&pkey_meth_table,
engine_unregister_all_pkey_meths, e,
nids, num_nids, 0);
}
return 1;
}
void ENGINE_register_all_pkey_meths(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_pkey_meths(e);
}
int ENGINE_set_default_pkey_meths(ENGINE *e)
{
if (e->pkey_meths) {
const int *nids;
int num_nids = e->pkey_meths(e, NULL, &nids, 0);
if (num_nids > 0)
return engine_table_register(&pkey_meth_table,
engine_unregister_all_pkey_meths, e,
nids, num_nids, 1);
}
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references) for a given pkey_meth 'nid'
*/
ENGINE *ENGINE_get_pkey_meth_engine(int nid)
{
return engine_table_select(&pkey_meth_table, nid);
}
/* Obtains a pkey_meth implementation from an ENGINE functional reference */
const EVP_PKEY_METHOD *ENGINE_get_pkey_meth(ENGINE *e, int nid)
{
EVP_PKEY_METHOD *ret;
ENGINE_PKEY_METHS_PTR fn = ENGINE_get_pkey_meths(e);
if (!fn || !fn(e, &ret, NULL, nid)) {
ENGINEerr(ENGINE_F_ENGINE_GET_PKEY_METH,
ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD);
return NULL;
}
return ret;
}
/* Gets the pkey_meth callback from an ENGINE structure */
ENGINE_PKEY_METHS_PTR ENGINE_get_pkey_meths(const ENGINE *e)
{
return e->pkey_meths;
}
/* Sets the pkey_meth callback in an ENGINE structure */
int ENGINE_set_pkey_meths(ENGINE *e, ENGINE_PKEY_METHS_PTR f)
{
e->pkey_meths = f;
return 1;
}
/*
* Internal function to free up EVP_PKEY_METHOD structures before an ENGINE
* is destroyed
*/
void engine_pkey_meths_free(ENGINE *e)
{
int i;
EVP_PKEY_METHOD *pkm;
if (e->pkey_meths) {
const int *pknids;
int npknids;
npknids = e->pkey_meths(e, NULL, &pknids, 0);
for (i = 0; i < npknids; i++) {
if (e->pkey_meths(e, &pkm, NULL, pknids[i])) {
EVP_PKEY_meth_free(pkm);
}
}
}
}

View file

@ -0,0 +1,72 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
static ENGINE_TABLE *rand_table = NULL;
static const int dummy_nid = 1;
void ENGINE_unregister_RAND(ENGINE *e)
{
engine_table_unregister(&rand_table, e);
}
static void engine_unregister_all_RAND(void)
{
engine_table_cleanup(&rand_table);
}
int ENGINE_register_RAND(ENGINE *e)
{
if (e->rand_meth)
return engine_table_register(&rand_table,
engine_unregister_all_RAND, e,
&dummy_nid, 1, 0);
return 1;
}
void ENGINE_register_all_RAND(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_RAND(e);
}
int ENGINE_set_default_RAND(ENGINE *e)
{
if (e->rand_meth)
return engine_table_register(&rand_table,
engine_unregister_all_RAND, e,
&dummy_nid, 1, 1);
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references).
*/
ENGINE *ENGINE_get_default_RAND(void)
{
return engine_table_select(&rand_table, dummy_nid);
}
/* Obtains an RAND implementation from an ENGINE functional reference */
const RAND_METHOD *ENGINE_get_RAND(const ENGINE *e)
{
return e->rand_meth;
}
/* Sets an RAND implementation in an ENGINE structure */
int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth)
{
e->rand_meth = rand_meth;
return 1;
}

View file

@ -0,0 +1,72 @@
/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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 "eng_int.h"
static ENGINE_TABLE *rsa_table = NULL;
static const int dummy_nid = 1;
void ENGINE_unregister_RSA(ENGINE *e)
{
engine_table_unregister(&rsa_table, e);
}
static void engine_unregister_all_RSA(void)
{
engine_table_cleanup(&rsa_table);
}
int ENGINE_register_RSA(ENGINE *e)
{
if (e->rsa_meth)
return engine_table_register(&rsa_table,
engine_unregister_all_RSA, e, &dummy_nid,
1, 0);
return 1;
}
void ENGINE_register_all_RSA(void)
{
ENGINE *e;
for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
ENGINE_register_RSA(e);
}
int ENGINE_set_default_RSA(ENGINE *e)
{
if (e->rsa_meth)
return engine_table_register(&rsa_table,
engine_unregister_all_RSA, e, &dummy_nid,
1, 1);
return 1;
}
/*
* Exposed API function to get a functional reference from the implementation
* table (ie. try to get a functional reference from the tabled structural
* references).
*/
ENGINE *ENGINE_get_default_RSA(void)
{
return engine_table_select(&rsa_table, dummy_nid);
}
/* Obtains an RSA implementation from an ENGINE functional reference */
const RSA_METHOD *ENGINE_get_RSA(const ENGINE *e)
{
return e->rsa_meth;
}
/* Sets an RSA implementation in an ENGINE structure */
int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth)
{
e->rsa_meth = rsa_meth;
return 1;
}