Commit 9e11fe0d authored by Richard Levitte's avatar Richard Levitte
Browse files

Replumbing: Add constructor of libcrypto internal method structures



This queries the provider for its available functionality (unless a
matching method structured is already cached, in which case that's
used instead), and creates method structure with the help of a passed
constructor.  The result is cached if the provider allows it (or if
caching is forced).

Reviewed-by: default avatarPaul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/8340)
parent 099bd339
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 x509v3 conf \

LIBS=../libcrypto
# The Core
SOURCE[../libcrypto]=provider_core.c
SOURCE[../libcrypto]=provider_core.c core_fetch.c

# Central utilities
SOURCE[../libcrypto]=\

crypto/core_fetch.c

0 → 100644
+97 −0
Original line number Diff line number Diff line
/*
 * 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/core.h>
#include "internal/cryptlib.h"
#include "internal/core.h"
#include "internal/property.h"
#include "internal/provider.h"

struct construct_data_st {
    OPENSSL_CTX *libctx;
    OSSL_METHOD_STORE *store;
    int operation_id;
    int force_store;
    OSSL_METHOD_CONSTRUCT_METHOD *mcm;
    void *mcm_data;
};

static int ossl_method_construct_this(OSSL_PROVIDER *provider, void *cbdata)
{
    struct construct_data_st *data = cbdata;
    int no_store = 0;    /* Assume caching is ok */
    const OSSL_ALGORITHM *map =
        ossl_provider_query_operation(provider, data->operation_id, &no_store);

    while (map->algorithm_name != NULL) {
        const OSSL_ALGORITHM *thismap = map++;
        void *method = NULL;

        if ((method = data->mcm->construct(thismap->implementation, provider,
                                            data->mcm_data)) == NULL)
            continue;

        if (data->force_store || !no_store) {
            /*
             * If we haven't been told not to store,
             * add to the global store
             */
            if (!data->mcm->put(data->libctx, NULL,
                                thismap->property_definition,
                                method, data->mcm_data)) {
                data->mcm->destruct(method);
                continue;
            }
        }

        if (!data->mcm->put(data->libctx, data->store,
                            thismap->property_definition,
                            method, data->mcm_data)) {
            data->mcm->destruct(method);
            continue;
        }
    }

    return 1;
}

void *ossl_method_construct(OPENSSL_CTX *libctx, int operation_id,
                            const char *name, const char *propquery,
                            int force_store,
                            OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data)
{
    void *method = NULL;

    if ((method = mcm->get(libctx, NULL, propquery, mcm_data)) == NULL) {
        struct construct_data_st cbdata;

        /*
         * We have a temporary store to be able to easily search among new
         * items, or items that should find themselves in the global store.
         */
        if ((cbdata.store = mcm->alloc_tmp_store()) == NULL)
            goto fin;

        cbdata.libctx = libctx;
        cbdata.operation_id = operation_id;
        cbdata.force_store = force_store;
        cbdata.mcm = mcm;
        cbdata.mcm_data = mcm_data;
        ossl_provider_forall_loaded(libctx, ossl_method_construct_this,
                                    &cbdata);

        method = mcm->get(libctx, cbdata.store, propquery, mcm_data);
        mcm->dealloc_tmp_store(cbdata.store);
    }

 fin:
    return method;
}
+133 −0
Original line number Diff line number Diff line
=pod

=head1 NAME

OSSL_METHOD_CONSTRUCT_METHOD, ossl_method_construct
- generic method constructor

=head1 SYNOPSIS

 #include "internal/core.h"

 struct ossl_method_construct_method_st {
     /* Create store */
     void *(*alloc_tmp_store)(void);
     /* Remove a store */
     void (*dealloc_tmp_store)(void *store);
     /* Get an already existing method from a store */
     void *(*get)(OPENSSL_CTX *libctx, void *store, const char *propquery,
                  void *data);
     /* Store a method in a store */
     int (*put)(OPENSSL_CTX *libctx, void *store, const char *propdef,
                void *method, void *data);
     /* Construct a new method */
     void *(*construct)(const OSSL_DISPATCH *fns, OSSL_PROVIDER *prov,
                        void *data);
     /* Destruct a method */
     void (*destruct)(void *method);
 };
 typedef struct ossl_method_construct_method OSSL_METHOD_CONSTRUCT_METHOD;

 void *ossl_method_construct(OPENSSL_CTX *ctx, int operation_id,
                             const char *name, const char *properties,
                             int force_cache,
                             OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data);

=head1 DESCRIPTION

All libcrypto sub-systems that want to create their own methods based
on provider dispatch tables need to do so in exactly the same way.
ossl_method_construct() does this while leaving it to the sub-systems
to define more precisely how the methods are created, stored, etc.

=head2 Functions

ossl_method_construct() creates a method by asking all available
providers for a dispatch table given an C<operation_id>, an algorithm
C<name> and a set of C<properties>, and then calling appropriate
functions given by the sub-system specific method creator through
C<mcm> and the data in C<mcm_data> (which is passed by
ossl_method_construct()).

=head2 Structures

A central part of constructing a sub-system specific method is to give
ossl_method_construct a set of functions, all in the
C<OSSL_METHOD_CONSTRUCT_METHOD> structure, which holds the following
function pointers:

=over 4

=item alloc_tmp_store()

Create a temporary method store.
This store is used to temporarily store methods for easier lookup, for
when the provider doesn't want its dispatch table stored in a longer
term cache.

=item dealloc_tmp_store()

Remove a temporary store.

=item get()

Look up an already existing method from a store.

The store may be given with C<store>.
B<NULL> is a valid value and means that a sub-system default store
must be used.
This default store should be stored in the library context C<libctx>.

The method to be looked up should be identified with data from C<data>
(which is the C<mcm_data> that was passed to ossl_construct_method())
and the provided property query C<propquery>.

=item put()

Places the C<method> created by the construct() function (see below)
in a store.

The store may be given with C<store>.
B<NULL> is a valid value and means that a sub-system default store
must be used.
This default store should be stored in the library context C<libctx>.

The method should be associated with the given property definition
C<propdef> and any identification data given through C<data> (which is
the C<mcm_data> that was passed to ossl_construct_method()).

=item construct()

Constructs a sub-system method given a dispatch table C<fns>.

The associated I<provider object> C<prov> is passed as well, to make
it possible for the sub-system constructor to keep a reference, which
is recommended.
If such a reference is kept, the I<provider object> reference counter
must be incremented, using ossl_provider_upref().

=item desctruct()

Destruct the given C<method>.

=back

=head1 RETURN VALUES

ossl_method_construct() returns a constructed method on success, or
B<NULL> on error.

=head1 HISTORY

This functionality was added to OpenSSL 3.0.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
+52 −0
Original line number Diff line number Diff line
/*
 * 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
 */

#ifndef OSSL_INTERNAL_CORE_H
# define OSSL_INTERNAL_CORE_H

/*
 * namespaces:
 *
 * ossl_method_         Core Method API
 */

/*
 * construct an arbitrary method from a dispatch table found by looking
 * up a match for the < operation_id, name, property > combination.
 * constructor and destructor are the constructor and destructor for that
 * arbitrary object.
 *
 * These objects are normally cached, unless the provider says not to cache.
 * However, force_cache can be used to force caching whatever the provider
 * says (for example, because the application knows better).
 */
typedef struct ossl_method_construct_method_st {
    /* Create store */
    void *(*alloc_tmp_store)(void);
    /* Remove a store */
    void (*dealloc_tmp_store)(void *store);
    /* Get an already existing method from a store */
    void *(*get)(OPENSSL_CTX *libctx, void *store, const char *propquery,
                 void *data);
    /* Store a method in a store */
    int (*put)(OPENSSL_CTX *libctx, void *store, const char *propdef,
               void *method, void *data);
    /* Construct a new method */
    void *(*construct)(const OSSL_DISPATCH *fns, OSSL_PROVIDER *prov,
                       void *data);
    /* Destruct a method */
    void (*destruct)(void *method);
} OSSL_METHOD_CONSTRUCT_METHOD;

void *ossl_method_construct(OPENSSL_CTX *ctx, int operation_id,
                            const char *name, const char *properties,
                            int force_cache,
                            OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data);

#endif