[openssl] master update

Richard Levitte levitte at openssl.org
Mon Mar 18 13:27:31 UTC 2019


The branch master has been updated
       via  c13d2ab439a9dcbbf22ef85a00603142b0a37779 (commit)
       via  a383083194b882a904ae66fcf74ebc348602407c (commit)
       via  7bb19a0f950dd87607133d526e31a083f35921fd (commit)
      from  f643deac417a3ccb27f77670bb2b136de49079d9 (commit)


- Log -----------------------------------------------------------------
commit c13d2ab439a9dcbbf22ef85a00603142b0a37779
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Feb 8 17:01:56 2019 +0100

    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 at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8341)

commit a383083194b882a904ae66fcf74ebc348602407c
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Mar 14 21:51:50 2019 +0100

    Replumbing: better reference counter control in ossl_method_construct()
    
    Fully assume that the method constructors use reference counting.
    Otherwise, we may leak memory, or loose track and do a double free.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8341)

commit 7bb19a0f950dd87607133d526e31a083f35921fd
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Mar 13 11:12:00 2019 +0100

    Replumbing: pass callback data to the algo destructor too
    
    All relevant OSSL_METHOD_CONSTRUCT_METHOD callbacks got the callback
    data passed to them, except 'destruct'.  There's no reason why it
    shouldn't get that pointer passed, so we make a small adjustment.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/8341)

-----------------------------------------------------------------------

Summary of changes:
 crypto/core_fetch.c                         |  32 ++--
 crypto/evp/build.info                       |   4 +
 crypto/evp/evp_fetch.c                      | 197 +++++++++++++++++++++++
 crypto/evp/evp_locl.h                       |  12 +-
 doc/internal/man3/evp_generic_fetch.pod     | 232 ++++++++++++++++++++++++++++
 doc/internal/man3/ossl_method_construct.pod |  14 +-
 include/internal/core.h                     |   2 +-
 7 files changed, 478 insertions(+), 15 deletions(-)
 create mode 100644 crypto/evp/evp_fetch.c
 create mode 100644 doc/internal/man3/evp_generic_fetch.pod

diff --git a/crypto/core_fetch.c b/crypto/core_fetch.c
index d2d7766..d38e132 100644
--- a/crypto/core_fetch.c
+++ b/crypto/core_fetch.c
@@ -39,25 +39,33 @@ static int ossl_method_construct_this(OSSL_PROVIDER *provider, void *cbdata)
                                             data->mcm_data)) == NULL)
             continue;
 
+        /*
+         * Note regarding putting the method in stores:
+         *
+         * we don't need to care if it actually got in or not here.
+         * If it didn't get in, it will simply not be available when
+         * ossl_method_construct() tries to get it from the store.
+         *
+         * It is *expected* that the put function increments the refcnt
+         * of the passed method.
+         */
+
         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;
-            }
+            data->mcm->put(data->libctx, NULL,
+                           thismap->property_definition,
+                           method, data->mcm_data);
         }
 
-        if (!data->mcm->put(data->libctx, data->store,
-                            thismap->property_definition,
-                            method, data->mcm_data)) {
-            data->mcm->destruct(method);
-            continue;
-        }
+        data->mcm->put(data->libctx, data->store,
+                       thismap->property_definition,
+                       method, data->mcm_data);
+
+        /* refcnt-- because we're dropping the reference */
+        data->mcm->destruct(method, data->mcm_data);
     }
 
     return 1;
diff --git a/crypto/evp/build.info b/crypto/evp/build.info
index 862afa8..10ba3a3 100644
--- a/crypto/evp/build.info
+++ b/crypto/evp/build.info
@@ -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
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
new file mode 100644
index 0000000..e50dd59
--- /dev/null
+++ b/crypto/evp/evp_fetch.c
@@ -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;
+}
diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h
index 95a9d5c..82e7bf8 100644
--- a/crypto/evp/evp_locl.h
+++ b/crypto/evp/evp_locl.h
@@ -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 *));
diff --git a/doc/internal/man3/evp_generic_fetch.pod b/doc/internal/man3/evp_generic_fetch.pod
new file mode 100644
index 0000000..b871cd1
--- /dev/null
+++ b/doc/internal/man3/evp_generic_fetch.pod
@@ -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
diff --git a/doc/internal/man3/ossl_method_construct.pod b/doc/internal/man3/ossl_method_construct.pod
index e91cfcd..3664635 100644
--- a/doc/internal/man3/ossl_method_construct.pod
+++ b/doc/internal/man3/ossl_method_construct.pod
@@ -49,6 +49,11 @@ 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()).
 
+This function assumes that the sub-system method creator implements
+reference counting and acts accordingly (i.e. it will call the
+sub-system destruct() method to decrement the reference count when
+appropriate).
+
 =head2 Structures
 
 A central part of constructing a sub-system specific method is to give
@@ -82,6 +87,8 @@ 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>.
 
+This function is expected to increment the method's reference count.
+
 =item put()
 
 Places the C<method> created by the construct() function (see below)
@@ -96,6 +103,8 @@ 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()).
 
+This function is expected to increment the C<method>'s reference count.
+
 =item construct()
 
 Constructs a sub-system method given a dispatch table C<fns>.
@@ -106,9 +115,12 @@ is recommended.
 If such a reference is kept, the I<provider object> reference counter
 must be incremented, using ossl_provider_upref().
 
+This function is expected to set the method's reference count to 1.
+
 =item desctruct()
 
-Destruct the given C<method>.
+Decrement the C<method>'s reference count, and destruct it when
+the reference count reaches zero.
 
 =back
 
diff --git a/include/internal/core.h b/include/internal/core.h
index 2f0df37..b395025 100644
--- a/include/internal/core.h
+++ b/include/internal/core.h
@@ -41,7 +41,7 @@ typedef struct ossl_method_construct_method_st {
     void *(*construct)(const OSSL_DISPATCH *fns, OSSL_PROVIDER *prov,
                        void *data);
     /* Destruct a method */
-    void (*destruct)(void *method);
+    void (*destruct)(void *method, void *data);
 } OSSL_METHOD_CONSTRUCT_METHOD;
 
 void *ossl_method_construct(OPENSSL_CTX *ctx, int operation_id,


More information about the openssl-commits mailing list