Add generic EVP method fetcher
This is an interface between Core dispatch table fetching and EVP_{method}_fetch(). All that's needed from the diverse method fetchers are the functions to create a method structure from a dispatch table, a function that ups the method reference counter and a function to free the method (in case of failure). This routine is internal to the EVP API andis therefore only made accessible within crypto/evp, by including evp_locl.h Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/8341)
This commit is contained in:
parent
a383083194
commit
c13d2ab439
4 changed files with 444 additions and 1 deletions
|
@ -16,6 +16,10 @@ SOURCE[../../libcrypto]=\
|
|||
e_chacha20_poly1305.c cmeth_lib.c \
|
||||
mac_lib.c c_allm.c pkey_mac.c
|
||||
|
||||
# New design
|
||||
SOURCE[../../libcrypto]=\
|
||||
evp_fetch.c
|
||||
|
||||
INCLUDE[e_aes.o]=.. ../modes
|
||||
INCLUDE[e_aes_cbc_hmac_sha1.o]=../modes
|
||||
INCLUDE[e_aes_cbc_hmac_sha256.o]=../modes
|
||||
|
|
197
crypto/evp/evp_fetch.c
Normal file
197
crypto/evp/evp_fetch.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/core.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/thread_once.h"
|
||||
#include "internal/asn1_int.h"
|
||||
#include "internal/property.h"
|
||||
#include "internal/core.h"
|
||||
#include "internal/evp_int.h" /* evp_locl.h needs it */
|
||||
#include "evp_locl.h"
|
||||
|
||||
/* The OpenSSL library context index for the default method store */
|
||||
static int default_method_store_index = -1;
|
||||
|
||||
static void default_method_store_free(void *vstore)
|
||||
{
|
||||
ossl_method_store_free(vstore);
|
||||
}
|
||||
|
||||
static void *default_method_store_new(void)
|
||||
{
|
||||
return ossl_method_store_new();
|
||||
}
|
||||
|
||||
|
||||
static const OPENSSL_CTX_METHOD default_method_store_method = {
|
||||
default_method_store_new,
|
||||
default_method_store_free,
|
||||
};
|
||||
|
||||
static int default_method_store_init(void)
|
||||
{
|
||||
default_method_store_index =
|
||||
openssl_ctx_new_index(&default_method_store_method);
|
||||
|
||||
return default_method_store_index != -1;
|
||||
}
|
||||
|
||||
static CRYPTO_ONCE default_method_store_init_flag = CRYPTO_ONCE_STATIC_INIT;
|
||||
DEFINE_RUN_ONCE_STATIC(do_default_method_store_init)
|
||||
{
|
||||
return OPENSSL_init_crypto(0, NULL)
|
||||
&& default_method_store_init();
|
||||
}
|
||||
|
||||
/* Data to be passed through ossl_method_construct() */
|
||||
struct method_data_st {
|
||||
const char *name;
|
||||
int nid;
|
||||
OSSL_METHOD_CONSTRUCT_METHOD *mcm;
|
||||
void *(*method_from_dispatch)(int nid, const OSSL_DISPATCH *,
|
||||
OSSL_PROVIDER *);
|
||||
int (*refcnt_up_method)(void *method);
|
||||
void (*destruct_method)(void *method);
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic routines to fetch / create EVP methods with ossl_method_construct()
|
||||
*/
|
||||
static void *alloc_tmp_method_store(void)
|
||||
{
|
||||
return ossl_method_store_new();
|
||||
}
|
||||
|
||||
static void dealloc_tmp_method_store(void *store)
|
||||
{
|
||||
if (store != NULL)
|
||||
ossl_method_store_free(store);
|
||||
}
|
||||
|
||||
static
|
||||
struct OSSL_METHOD_STORE *get_default_method_store(OPENSSL_CTX *libctx)
|
||||
{
|
||||
if (!RUN_ONCE(&default_method_store_init_flag,
|
||||
do_default_method_store_init))
|
||||
return NULL;
|
||||
return openssl_ctx_get_data(libctx, default_method_store_index);
|
||||
}
|
||||
|
||||
static void *get_method_from_store(OPENSSL_CTX *libctx, void *store,
|
||||
const char *propquery, void *data)
|
||||
{
|
||||
struct method_data_st *methdata = data;
|
||||
void *method = NULL;
|
||||
|
||||
if (store == NULL
|
||||
&& (store = get_default_method_store(libctx)) == NULL)
|
||||
return NULL;
|
||||
|
||||
(void)ossl_method_store_fetch(store, methdata->nid, propquery, &method);
|
||||
|
||||
if (method != NULL
|
||||
&& !methdata->refcnt_up_method(method)) {
|
||||
method = NULL;
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
static int put_method_in_store(OPENSSL_CTX *libctx, void *store,
|
||||
const char *propdef, void *method,
|
||||
void *data)
|
||||
{
|
||||
struct method_data_st *methdata = data;
|
||||
|
||||
if (store == NULL
|
||||
&& (store = get_default_method_store(libctx)) == NULL)
|
||||
return 0;
|
||||
|
||||
if (methdata->refcnt_up_method(method)
|
||||
&& ossl_method_store_add(store, methdata->nid, propdef, method,
|
||||
methdata->destruct_method))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *construct_method(const OSSL_DISPATCH *fns, OSSL_PROVIDER *prov,
|
||||
void *data)
|
||||
{
|
||||
struct method_data_st *methdata = data;
|
||||
void *method = NULL;
|
||||
|
||||
if (methdata->nid == NID_undef) {
|
||||
/* Create a new NID for that name on the fly */
|
||||
ASN1_OBJECT tmpobj;
|
||||
|
||||
/* This is the same as OBJ_create() but without requiring a OID */
|
||||
tmpobj.nid = OBJ_new_nid(1);
|
||||
tmpobj.sn = tmpobj.ln = methdata->name;
|
||||
tmpobj.flags = ASN1_OBJECT_FLAG_DYNAMIC;
|
||||
tmpobj.length = 0;
|
||||
tmpobj.data = NULL;
|
||||
|
||||
methdata->nid = OBJ_add_object(&tmpobj);
|
||||
}
|
||||
|
||||
if (methdata->nid == NID_undef)
|
||||
return NULL;
|
||||
|
||||
method = methdata->method_from_dispatch(methdata->nid, fns, prov);
|
||||
if (method == NULL)
|
||||
return NULL;
|
||||
return method;
|
||||
}
|
||||
|
||||
static void destruct_method(void *method, void *data)
|
||||
{
|
||||
struct method_data_st *methdata = data;
|
||||
|
||||
methdata->destruct_method(method);
|
||||
}
|
||||
|
||||
void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
|
||||
const char *algorithm, const char *properties,
|
||||
void *(*new_method)(int nid, const OSSL_DISPATCH *fns,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*upref_method)(void *),
|
||||
void (*free_method)(void *))
|
||||
{
|
||||
int nid = OBJ_sn2nid(algorithm);
|
||||
void *method = NULL;
|
||||
|
||||
if (nid == NID_undef
|
||||
|| !ossl_method_store_cache_get(NULL, nid, properties, &method)) {
|
||||
OSSL_METHOD_CONSTRUCT_METHOD mcm = {
|
||||
alloc_tmp_method_store,
|
||||
dealloc_tmp_method_store,
|
||||
get_method_from_store,
|
||||
put_method_in_store,
|
||||
construct_method,
|
||||
destruct_method
|
||||
};
|
||||
struct method_data_st mcmdata;
|
||||
|
||||
mcmdata.nid = nid;
|
||||
mcmdata.mcm = &mcm;
|
||||
mcmdata.method_from_dispatch = new_method;
|
||||
mcmdata.destruct_method = free_method;
|
||||
mcmdata.refcnt_up_method = upref_method;
|
||||
mcmdata.destruct_method = free_method;
|
||||
method = ossl_method_construct(libctx, operation_id, algorithm,
|
||||
properties, 0 /* !force_cache */,
|
||||
&mcm, &mcmdata);
|
||||
ossl_method_store_cache_set(NULL, nid, properties, method);
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 2000-2019 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
|
@ -76,3 +76,13 @@ typedef struct evp_pbe_st EVP_PBE_CTL;
|
|||
DEFINE_STACK_OF(EVP_PBE_CTL)
|
||||
|
||||
int is_partially_overlapping(const void *ptr1, const void *ptr2, int len);
|
||||
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/core.h>
|
||||
|
||||
void *evp_generic_fetch(OPENSSL_CTX *ctx, int operation_id,
|
||||
const char *algorithm, const char *properties,
|
||||
void *(*new_method)(int nid, const OSSL_DISPATCH *fns,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*upref_method)(void *),
|
||||
void (*free_method)(void *));
|
||||
|
|
232
doc/internal/man3/evp_generic_fetch.pod
Normal file
232
doc/internal/man3/evp_generic_fetch.pod
Normal file
|
@ -0,0 +1,232 @@
|
|||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
evp_generic_fetch - generic algorithm fetcher and method creator for EVP
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
/* Only for EVP source */
|
||||
#include "evp_locl.h"
|
||||
|
||||
void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
|
||||
const char *algorithm, const char *properties,
|
||||
void *(*new_method)(int nid, const OSSL_DISPATCH *fns,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*upref_method)(void *),
|
||||
void (*free_method)(void *));
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
evp_generic_fetch() calls ossl_method_construct() with the given
|
||||
C<libctx>, C<operation_id>, C<algorithm>, and C<properties> and uses
|
||||
it to create an EVP method with the help of the functions
|
||||
C<new_method>, C<upref_method>, and C<free_method>.
|
||||
|
||||
The three functions are supposed to:
|
||||
|
||||
=over 4
|
||||
|
||||
=item new_method()
|
||||
|
||||
creates an internal method from function pointers found in the
|
||||
dispatch table C<fns>.
|
||||
|
||||
=item upref_method()
|
||||
|
||||
increments the reference counter for the given method, if there is
|
||||
one.
|
||||
|
||||
=item free_method()
|
||||
|
||||
frees the given method.
|
||||
|
||||
=back
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
evp_generic_fetch() returns a method on success, or B<NULL> on error.
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
This is a short example of the fictitious EVP API and operation called
|
||||
C<EVP_FOO>.
|
||||
|
||||
To begin with, let's assume something like this in
|
||||
C<include/openssl/core_numbers.h>:
|
||||
|
||||
#define OSSL_OP_FOO 100
|
||||
|
||||
#define OSSL_OP_FOO_NEWCTX_FUNC 2001
|
||||
#define OSSL_OP_FOO_INIT 2002
|
||||
#define OSSL_OP_FOO_OPERATE 2003
|
||||
#define OSSL_OP_FOO_CLEANCTX_FUNC 2004
|
||||
#define OSSL_OP_FOO_FREECTX_FUNC 2005
|
||||
OSSL_CORE_MAKE_FUNC(void *,OP_foo_newctx,(void))
|
||||
OSSL_CORE_MAKE_FUNC(int,OP_foo_init,(void *vctx))
|
||||
OSSL_CORE_MAKE_FUNC(int,OP_foo_operate,(void *vctx,
|
||||
unsigned char *out, size_t *out_l,
|
||||
unsigned char *in, size_t in_l))
|
||||
OSSL_CORE_MAKE_FUNC(void,OP_foo_cleanctx,(void *vctx))
|
||||
OSSL_CORE_MAKE_FUNC(void,OP_foo_freectx,(void *vctx))
|
||||
|
||||
And here's the implementation of the FOO method fetcher:
|
||||
|
||||
/* typedef struct evp_foo_st EVP_FOO */
|
||||
struct evp_foo_st {
|
||||
OSSL_PROVIDER *prov;
|
||||
int nid;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
OSSL_OP_foo_newctx_fn *newctx;
|
||||
OSSL_OP_foo_init_fn *init;
|
||||
OSSL_OP_foo_operate_fn *operate;
|
||||
OSSL_OP_foo_cleanctx_fn *cleanctx;
|
||||
OSSL_OP_foo_freectx_fn *freectx;
|
||||
};
|
||||
|
||||
/*
|
||||
* In this example, we have a public method creator and destructor.
|
||||
* It's not absolutely necessary, but is in the spirit of OpenSSL.
|
||||
*/
|
||||
EVP_FOO *EVP_FOO_meth_from_dispatch(int foo_type, const OSSL_DISPATCH *fns,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
EVP_FOO *foo = NULL;
|
||||
|
||||
if ((foo = OPENSSL_zalloc(sizeof(*foo))) == NULL)
|
||||
return NULL;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_OP_FOO_NEWCTX_FUNC:
|
||||
foo->newctx = OSSL_get_OP_foo_newctx(fns);
|
||||
break;
|
||||
case OSSL_OP_FOO_INIT:
|
||||
foo->init = OSSL_get_OP_foo_init(fns);
|
||||
break;
|
||||
case OSSL_OP_FOO_OPERATE:
|
||||
foo->operate = OSSL_get_OP_foo_operate(fns);
|
||||
break;
|
||||
case OSSL_OP_FOO_CLEANCTX_FUNC:
|
||||
foo->cleanctx = OSSL_get_OP_foo_cleanctx(fns);
|
||||
break;
|
||||
case OSSL_OP_FOO_FREECTX_FUNC:
|
||||
foo->freectx = OSSL_get_OP_foo_freectx(fns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
foo->nid = foo_type;
|
||||
foo->prov = prov;
|
||||
if (prov)
|
||||
ossl_provider_upref(prov);
|
||||
|
||||
return foo;
|
||||
}
|
||||
|
||||
EVP_FOO_meth_free(EVP_FOO *foo)
|
||||
{
|
||||
if (foo != NULL) {
|
||||
OSSL_PROVIDER *prov = foo->prov;
|
||||
|
||||
OPENSSL_free(foo);
|
||||
ossl_provider_free(prov);
|
||||
}
|
||||
}
|
||||
|
||||
static void *foo_from_dispatch(int nid, const OSSL_DISPATCH *fns,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
return EVP_FOO_meth_from_dispatch(nid, fns, prov);
|
||||
}
|
||||
|
||||
static int foo_upref(void *vfoo)
|
||||
{
|
||||
EVP_FOO *foo = vfoo;
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&foo->refcnt, &ref, foo_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void foo_free(void *vfoo)
|
||||
{
|
||||
EVP_FOO_meth_free(vfoo);
|
||||
}
|
||||
|
||||
EVP_FOO *EVP_FOO_fetch(OPENSSL_CTX *ctx,
|
||||
const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(ctx, OSSL_OP_FOO, algorithm, properties,
|
||||
foo_from_dispatch, foo_upref, foo_free);
|
||||
}
|
||||
|
||||
And finally, the library functions:
|
||||
|
||||
/* typedef struct evp_foo_st EVP_FOO_CTX */
|
||||
struct evp_foo_ctx_st {
|
||||
const EVP_FOO *foo;
|
||||
void *provctx; /* corresponding provider context */
|
||||
};
|
||||
|
||||
int EVP_FOO_CTX_reset(EVP_FOO_CTX *c)
|
||||
{
|
||||
if (c == NULL)
|
||||
return 1;
|
||||
if (c->foo != NULL && c->foo->cleanctx != NULL)
|
||||
c->foo->cleanctx(c->provctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
EVP_FOO_CTX *EVP_FOO_CTX_new(void)
|
||||
{
|
||||
return OPENSSL_zalloc(sizeof(EVP_FOO_CTX));
|
||||
}
|
||||
|
||||
void EVP_FOO_CTX_free(EVP_FOO_CTX *c)
|
||||
{
|
||||
EVP_FOO_CTX_reset(c);
|
||||
c->foo->freectx(c->provctx);
|
||||
OPENSSL_free(c);
|
||||
}
|
||||
|
||||
int EVP_FooInit(EVP_FOO_CTX *c, const EVP_FOO *foo)
|
||||
{
|
||||
int ok = 1;
|
||||
|
||||
c->foo = foo;
|
||||
if (c->provctx == NULL)
|
||||
c->provctx = c->foo->newctx();
|
||||
|
||||
ok = c->foo->init(c->provctx);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int EVP_FooOperate(EVP_FOO_CTX *c, unsigned char *out, size_t *outl,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
int ok = 1;
|
||||
|
||||
ok = c->foo->update(c->provctx, out, inl, &outl, in, inl);
|
||||
return ok;
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<ossl_method_construct>
|
||||
|
||||
=head1 HISTORY
|
||||
|
||||
The functions described here were all added in OpenSSL 3.0.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
this file except in compliance with the License. You can obtain a copy
|
||||
in the file LICENSE in the source distribution or at
|
||||
L<https://www.openssl.org/source/license.html>.
|
||||
|
||||
=cut
|
Loading…
Reference in a new issue