]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
design proposal: fast param location outline
authorPauli <pauli@openssl.org>
Thu, 11 May 2023 07:14:26 +0000 (17:14 +1000)
committerPauli <pauli@openssl.org>
Wed, 28 Jun 2023 07:15:08 +0000 (17:15 +1000)
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/20940)

doc/designs/fast-param-find.md [new file with mode: 0644]

diff --git a/doc/designs/fast-param-find.md b/doc/designs/fast-param-find.md
new file mode 100644 (file)
index 0000000..02460ce
--- /dev/null
@@ -0,0 +1,345 @@
+Proposal for OSSL_PARAM futures
+===============================
+
+Format:
+
+```perl
+{-
+use OpenSSL::paramnames qw(produce_param_handlers);
+-}
+
+/*
+ * Machine generated parameter handling
+ * generated by util/perl/OpenSSL/paramnames.pm
+ */
+{-
+produce_param_handlers(
+    'name' => 'kdf_scrypt',
+    'functions' => 'both',   # getter or setter being the other options
+    'prologue' => "KDF_SCRYPT *ctx = vctx;",
+    "static" => "yes",      # "yes" to generate static functions (default) or
+                            # "no" to not
+    'params' => (
+        'KDF_PARAM_PASSWORD' => (
+            'type' => 'octet string',
+            'access' => 'writeonly',
+            'setaction' => qq(
+                if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
+                    return 0;
+            ),
+        ),
+
+        'KDF_PARAM_SALT' => (
+            'type' => 'octet string',
+            'access' => 'readwrite',
+            'setaction' => qq(
+                if (!scrypt_set_membuf(&ctx->salt, &ctx->salt_len, p))
+                    return 0;
+            ),
+            'getaction' => qq(
+                p->return_size = ctx->salt_len;
+                if (p->data_size >= ctx->salt_len)
+                    memcpy(p->data, ctx->salt, p->data_size >= ctx->salt_len);
+            ),
+        ),
+
+        'KDF_PARAM_SCRYPT_N' => (
+            'type' => 'integer',
+            'ctype' => 'uint64_t',
+            'access' => 'readwrite',
+            'field' => "ctx->N",
+            'sanitycheck' => "value > 1 && is_power_of_two(value)"
+        ),
+
+        'KDF_PARAM_SCRYPT_R' => (
+            'type' => 'integer',
+            'ctype' => 'uint64_t',
+            'access' => 'readwrite',
+            'field' => "ctx->r",
+            'sanitycheck' => "value >= 1",
+        ),
+
+        'KDF_PARAM_SCRYPT_P' => (
+            'type' => 'integer',
+            'ctype' => 'uint64_t',
+            'access' => 'readwrite',
+            'field' => "ctx->p",
+            'sanitycheck' => "value >= 1",
+        ),
+
+        'KDF_PARAM_SCRYPT_MAXMEM' => (
+            'type' => 'integer',
+            'ctype' => 'uint64_t',
+            'access' => 'readwrite',
+            'field' => "ctx->maxmem_bytes",
+            'sanitycheck' => "value >= 1",
+        ),
+
+        'KDF_PARAM_PROPERTIES' => (
+            'type' => 'utf8_string',
+            'access' => 'readwrite',
+            'setaction' => qq(
+                if (!set_property_query(ctx, p->data) || !set_digest(ctx))
+                    return 0;
+            ),
+        ),
+
+        'KDF_PARAM_SIZE' => (
+            'type' => 'integer',
+            'ctype' => 'size_t',
+            'access' => 'readonly',
+            'field' => "SIZE_MAX",
+        ),
+    );
+);
+-}
+/* End of generated code */
+```
+
+THe top level attributes are:
+
+- "name" is the name the functions will derive from e.g. "kdf_scrypt" to this
+  will be appended _[gs]et[_ctx]_params
+- "functions" is the functions to generate.  By default both setters and
+  getters but either can be omitted.
+- "prologue" defines some introductory code emited in the generated functions.
+  Function arguments are: `void *vctx, OSSL_PARAM params[]` and this
+  can be used to specialise the void pointer or declare locals.
+- "epilogue" defines some post decode code emited in the generated function
+- "params" defines the parameters both gettable and settable
+
+Within the "params" the fields specify each parameter by label.
+
+Each parameter is then specialised with attributes:
+
+- "type" is the OSSL_PARAM type
+- "ctype" is the underlying C type (e.g. for an integer parameter size_t
+  could be the C type)
+- "access" is readwrite, readonly or writeonly.  This determines if the
+  parameter is a settable, gettable or both
+- "field" is an accessor to the field itself
+- "sanitycheck" is a validation check for the parameter.  If present, code
+  will be generated `if (!(sanitycheck)) return 0;`
+  The local variable `var` will contain the C value if specified.
+- "setaction" is C code to execute when the parameter is being set.  It will
+  define an OSSL_PARAM pointer p to set.
+- "code" set to "no" skips code generation for this parameter, it defaults
+  to "yes" which generates handlers.  This is useful when a parameter
+  is duplicated with differenting types (e.g. utf8 string and integer).
+- "published" set to "yes" includes the parameter in the gettable/settable
+  lists.  Set to "no" and it isn't included (but will still be processed).
+  It defaults to "yes".
+
+- Flags include:
+  - nostatic: do not make the function static
+  - nocode: do not generate code for this parameter
+    - This allows, e.g., two different types for a parameter (int & string)
+  - unpublished: do not generate this parameter in the gettable/settable list
+    - "engine" is the only one like this
+  - readonly: create a getter but not a setter
+  - writeonly: create a setting but not a getter
+
+The idea is that the gettable and get functions will be simultaneously
+generated along with fast decoder to look up parameter names quickly.
+
+The getter and setter functions will be pre-populated with some local variable:
+
+```c
+    OSSL_PARAM *p; /* The matching parameter */
+    type val;      /* The value of the parameter after a get/set call */
+                   /* (for C types) */
+```
+
+A worked example for scrypt:
+
+Would generate something along the lines of:
+
+```c
+enum kdf_scrypt_ctx_param_e {
+    kdf_scrypt_ctx_param_INVALID,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PASSWORD,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PROPERTIES,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SALT,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_MAXMEM,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_N,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_P,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_R,
+    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SIZE
+};
+
+
+static enum kdf_scrypt_ctx_param_e kdf_scrypt_ctx_lookup(const OSSL_PARAM *p) {
+    /* magic decoder */
+    return kdf_scrypt_ctx_param_INVALID;
+}
+
+static int kdf_scrypt_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *p;
+    KDF_SCRYPT *ctx = vctx;
+
+    if (params == NULL)
+        return 1;
+
+    for (p = params; p->key != NULL; p++) {
+        switch (kdf_scrypt_ctx_lookup(p)) {
+        default:
+            break;
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PASSWORD:
+            if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
+                return 0;
+            break;
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SALT:
+            if (!scrypt_set_membuf(&ctx->salt, &ctx->salt_len, p))
+                return 0;
+            break;
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_N: {
+            uint64_t value;
+
+            if (!OSSL_PARAM_get_uint64(p, &value) {
+                if (!(value > 1 && is_power_of_two(u64_value)))
+                    return 0;
+                ctx->N = value;
+            }
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_R: {
+            uint64_t value;
+
+            if (!OSSL_PARAM_get_uint64(p, &value) {
+                if (!(value >= 1))
+                    return 0;
+                ctx->r = value;
+            }
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_P: {
+            uint64_t value;
+
+            if (!OSSL_PARAM_get_uint64(p, &value) {
+                if (!(value >= 1))
+                    return 0;
+                ctx->p = value;
+            }
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_MAXMEM: {
+            uint64_t value;
+
+            if (!OSSL_PARAM_get_uint64(p, &value) {
+                if (!(value >= 1))
+                    return 0;
+                ctx->p = value;
+            }
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PROPERTIES:
+            if (p != NULL) {
+                if (p->data_type != OSSL_PARAM_UTF8_STRING) {
+                    if (!set_property_query(ctx, p->data) || !set_digest(ctx))
+                        return 0;
+                    }
+            }
+        }
+    }
+
+    return 1;
+}
+
+static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(ossl_unused void *ctx,
+                                                        ossl_unused void *p_ctx)
+{
+    static const OSSL_PARAM known_settable_ctx_params[] = {
+        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0),
+        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0),
+        OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_N, NULL),
+        OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_R, NULL),
+        OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_P, NULL),
+        OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, NULL),
+        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
+        OSSL_PARAM_END
+    };
+    return known_settable_ctx_params;
+}
+
+static int kdf_scrypt_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+    const OSSL_PARAM *p;
+    KDF_SCRYPT *ctx = vctx;
+
+    if (params == NULL)
+        return 1;
+
+    for (p = params; p->key != NULL; p++) {
+        switch (kdf_scrypt_ctx_lookup(p)) {
+        default:
+            break;
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PASSWORD:
+            if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
+                return 0;
+            break;
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SALT:
+            p->return_size = ctx->salt_len;
+            if (p->data_size >= ctx->salt_len)
+                memcpy(p->data, ctx->salt, ctx->salt_len);
+            break;
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_N: {
+            if (!OSSL_PARAM_set_uint64(p, &ctx->N)
+                return 0;
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_R: {
+            if (!OSSL_PARAM_set_uint64(p, &ctx->r)
+                return 0;
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_P: {
+            if (!OSSL_PARAM_set_uint64(p, &ctx->p)
+                return 0;
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_MAXMEM: {
+            if (!OSSL_PARAM_set_uint64(p, &ctx->maxmem)
+                return 0;
+            break;
+        }
+
+        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PROPERTIES:
+            if (p->data_type != OSSL_PARAM_UTF8_STRING) {
+                if (!set_property_query(ctx, p->data) || !set_digest(ctx))
+                    return 0;
+            }
+            break;
+
+        case kdf_scrypt_ctx_param_KDF_PARAM_SIZE:
+            if (!OSSL_PARAM_set_size_t(p, SIZE_MAX))
+                return 0;
+            break;
+        }
+    }
+    return 1;
+}
+
+static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(ossl_unused void *ctx,
+                                                        ossl_unused void *p_ctx)
+{
+    static const OSSL_PARAM known_gettable_ctx_params[] = {
+        OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+        OSSL_PARAM_END
+    };
+    return known_gettable_ctx_params;
+}
+```