summaryrefslogtreecommitdiffstats
path: root/doc/designs
diff options
context:
space:
mode:
authorPauli <pauli@openssl.org>2023-05-11 17:14:26 +1000
committerPauli <pauli@openssl.org>2023-06-28 17:15:08 +1000
commit15821a48e558d595895fc8cf1c9c038d7c455550 (patch)
treebd359ddb55e3b4b8ab39f51ffdf4a31e41f27408 /doc/designs
parent9f0cc5d09a89731f1cd9b111f12aa3ac9667b6a0 (diff)
design proposal: fast param location outline
Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/20940)
Diffstat (limited to 'doc/designs')
-rw-r--r--doc/designs/fast-param-find.md345
1 files changed, 345 insertions, 0 deletions
diff --git a/doc/designs/fast-param-find.md b/doc/designs/fast-param-find.md
new file mode 100644
index 0000000000..02460ce4bd
--- /dev/null
+++ b/doc/designs/fast-param-find.md
@@ -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;
+}
+```