xref: /openssl/doc/designs/fast-param-find.md (revision 6a2b8269)
1Proposal for OSSL_PARAM futures
2===============================
3
4Format:
5
6```perl
7{-
8use OpenSSL::paramnames qw(produce_param_handlers);
9-}
10
11/*
12 * Machine generated parameter handling
13 * generated by util/perl/OpenSSL/paramnames.pm
14 */
15{-
16produce_param_handlers(
17    'name' => 'kdf_scrypt',
18    'functions' => 'both',   # getter or setter being the other options
19    'prologue' => "KDF_SCRYPT *ctx = vctx;",
20    "static" => "yes",      # "yes" to generate static functions (default) or
21                            # "no" to not
22    'params' => (
23        'KDF_PARAM_PASSWORD' => (
24            'type' => 'octet string',
25            'access' => 'writeonly',
26            'setaction' => qq(
27                if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
28                    return 0;
29            ),
30        ),
31
32        'KDF_PARAM_SALT' => (
33            'type' => 'octet string',
34            'access' => 'readwrite',
35            'setaction' => qq(
36                if (!scrypt_set_membuf(&ctx->salt, &ctx->salt_len, p))
37                    return 0;
38            ),
39            'getaction' => qq(
40                p->return_size = ctx->salt_len;
41                if (p->data_size >= ctx->salt_len)
42                    memcpy(p->data, ctx->salt, p->data_size >= ctx->salt_len);
43            ),
44        ),
45
46        'KDF_PARAM_SCRYPT_N' => (
47            'type' => 'integer',
48            'ctype' => 'uint64_t',
49            'access' => 'readwrite',
50            'field' => "ctx->N",
51            'sanitycheck' => "value > 1 && is_power_of_two(value)"
52        ),
53
54        'KDF_PARAM_SCRYPT_R' => (
55            'type' => 'integer',
56            'ctype' => 'uint64_t',
57            'access' => 'readwrite',
58            'field' => "ctx->r",
59            'sanitycheck' => "value >= 1",
60        ),
61
62        'KDF_PARAM_SCRYPT_P' => (
63            'type' => 'integer',
64            'ctype' => 'uint64_t',
65            'access' => 'readwrite',
66            'field' => "ctx->p",
67            'sanitycheck' => "value >= 1",
68        ),
69
70        'KDF_PARAM_SCRYPT_MAXMEM' => (
71            'type' => 'integer',
72            'ctype' => 'uint64_t',
73            'access' => 'readwrite',
74            'field' => "ctx->maxmem_bytes",
75            'sanitycheck' => "value >= 1",
76        ),
77
78        'KDF_PARAM_PROPERTIES' => (
79            'type' => 'utf8_string',
80            'access' => 'readwrite',
81            'setaction' => qq(
82                if (!set_property_query(ctx, p->data) || !set_digest(ctx))
83                    return 0;
84            ),
85        ),
86
87        'KDF_PARAM_SIZE' => (
88            'type' => 'integer',
89            'ctype' => 'size_t',
90            'access' => 'readonly',
91            'field' => "SIZE_MAX",
92        ),
93    );
94);
95-}
96/* End of generated code */
97```
98
99THe top level attributes are:
100
101- "name" is the name the functions will derive from e.g. "kdf_scrypt" to this
102  will be appended _[gs]et[_ctx]_params
103- "functions" is the functions to generate.  By default both setters and
104  getters but either can be omitted.
105- "prologue" defines some introductory code emitted in the generated functions.
106  Function arguments are: `void *vctx, OSSL_PARAM params[]` and this
107  can be used to specialise the void pointer or declare locals.
108- "epilogue" defines some post decode code emitted in the generated function
109- "params" defines the parameters both gettable and settable
110
111Within the "params" the fields specify each parameter by label.
112
113Each parameter is then specialised with attributes:
114
115- "type" is the OSSL_PARAM type
116- "ctype" is the underlying C type (e.g. for an integer parameter size_t
117  could be the C type)
118- "access" is readwrite, readonly or writeonly.  This determines if the
119  parameter is a settable, gettable or both
120- "field" is an accessor to the field itself
121- "sanitycheck" is a validation check for the parameter.  If present, code
122  will be generated `if (!(sanitycheck)) return 0;`
123  The local variable `var` will contain the C value if specified.
124- "setaction" is C code to execute when the parameter is being set.  It will
125  define an OSSL_PARAM pointer p to set.
126- "code" set to "no" skips code generation for this parameter, it defaults
127  to "yes" which generates handlers.  This is useful when a parameter
128  is duplicated with differenting types (e.g. utf8 string and integer).
129- "published" set to "yes" includes the parameter in the gettable/settable
130  lists.  Set to "no" and it isn't included (but will still be processed).
131  It defaults to "yes".
132
133- Flags include:
134  - nostatic: do not make the function static
135  - nocode: do not generate code for this parameter
136    - This allows, e.g., two different types for a parameter (int & string)
137  - unpublished: do not generate this parameter in the gettable/settable list
138    - "engine" is the only one like this
139  - readonly: create a getter but not a setter
140  - writeonly: create a setting but not a getter
141
142The idea is that the gettable and get functions will be simultaneously
143generated along with fast decoder to look up parameter names quickly.
144
145The getter and setter functions will be pre-populated with some local variable:
146
147```c
148    OSSL_PARAM *p; /* The matching parameter */
149    type val;      /* The value of the parameter after a get/set call */
150                   /* (for C types) */
151```
152
153A worked example for scrypt:
154
155Would generate something along the lines of:
156
157```c
158enum kdf_scrypt_ctx_param_e {
159    kdf_scrypt_ctx_param_INVALID,
160    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PASSWORD,
161    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PROPERTIES,
162    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SALT,
163    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_MAXMEM,
164    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_N,
165    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_P,
166    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_R,
167    kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SIZE
168};
169
170
171static enum kdf_scrypt_ctx_param_e kdf_scrypt_ctx_lookup(const OSSL_PARAM *p) {
172    /* magic decoder */
173    return kdf_scrypt_ctx_param_INVALID;
174}
175
176static int kdf_scrypt_set_ctx_params(void *vctx, const OSSL_PARAM params[])
177{
178    const OSSL_PARAM *p;
179    KDF_SCRYPT *ctx = vctx;
180
181    if (params == NULL)
182        return 1;
183
184    for (p = params; p->key != NULL; p++) {
185        switch (kdf_scrypt_ctx_lookup(p)) {
186        default:
187            break;
188
189        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PASSWORD:
190            if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
191                return 0;
192            break;
193
194        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SALT:
195            if (!scrypt_set_membuf(&ctx->salt, &ctx->salt_len, p))
196                return 0;
197            break;
198
199        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_N: {
200            uint64_t value;
201
202            if (!OSSL_PARAM_get_uint64(p, &value) {
203                if (!(value > 1 && is_power_of_two(u64_value)))
204                    return 0;
205                ctx->N = value;
206            }
207            break;
208        }
209
210        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_R: {
211            uint64_t value;
212
213            if (!OSSL_PARAM_get_uint64(p, &value) {
214                if (!(value >= 1))
215                    return 0;
216                ctx->r = value;
217            }
218            break;
219        }
220
221        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_P: {
222            uint64_t value;
223
224            if (!OSSL_PARAM_get_uint64(p, &value) {
225                if (!(value >= 1))
226                    return 0;
227                ctx->p = value;
228            }
229            break;
230        }
231
232        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_MAXMEM: {
233            uint64_t value;
234
235            if (!OSSL_PARAM_get_uint64(p, &value) {
236                if (!(value >= 1))
237                    return 0;
238                ctx->p = value;
239            }
240            break;
241        }
242
243        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PROPERTIES:
244            if (p != NULL) {
245                if (p->data_type != OSSL_PARAM_UTF8_STRING) {
246                    if (!set_property_query(ctx, p->data) || !set_digest(ctx))
247                        return 0;
248                    }
249            }
250        }
251    }
252
253    return 1;
254}
255
256static const OSSL_PARAM *kdf_scrypt_settable_ctx_params(ossl_unused void *ctx,
257                                                        ossl_unused void *p_ctx)
258{
259    static const OSSL_PARAM known_settable_ctx_params[] = {
260        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PASSWORD, NULL, 0),
261        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0),
262        OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_N, NULL),
263        OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_R, NULL),
264        OSSL_PARAM_uint32(OSSL_KDF_PARAM_SCRYPT_P, NULL),
265        OSSL_PARAM_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, NULL),
266        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
267        OSSL_PARAM_END
268    };
269    return known_settable_ctx_params;
270}
271
272static int kdf_scrypt_get_ctx_params(void *vctx, OSSL_PARAM params[])
273{
274    const OSSL_PARAM *p;
275    KDF_SCRYPT *ctx = vctx;
276
277    if (params == NULL)
278        return 1;
279
280    for (p = params; p->key != NULL; p++) {
281        switch (kdf_scrypt_ctx_lookup(p)) {
282        default:
283            break;
284
285        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PASSWORD:
286            if (!scrypt_set_membuf(&ctx->pass, &ctx->pass_len, p))
287                return 0;
288            break;
289
290        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SALT:
291            p->return_size = ctx->salt_len;
292            if (p->data_size >= ctx->salt_len)
293                memcpy(p->data, ctx->salt, ctx->salt_len);
294            break;
295
296        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_N: {
297            if (!OSSL_PARAM_set_uint64(p, &ctx->N)
298                return 0;
299            break;
300        }
301
302        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_R: {
303            if (!OSSL_PARAM_set_uint64(p, &ctx->r)
304                return 0;
305            break;
306        }
307
308        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_P: {
309            if (!OSSL_PARAM_set_uint64(p, &ctx->p)
310                return 0;
311            break;
312        }
313
314        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_SCRYPT_MAXMEM: {
315            if (!OSSL_PARAM_set_uint64(p, &ctx->maxmem)
316                return 0;
317            break;
318        }
319
320        case kdf_scrypt_ctx_param_OSSL_KDF_PARAM_PROPERTIES:
321            if (p->data_type != OSSL_PARAM_UTF8_STRING) {
322                if (!set_property_query(ctx, p->data) || !set_digest(ctx))
323                    return 0;
324            }
325            break;
326
327        case kdf_scrypt_ctx_param_KDF_PARAM_SIZE:
328            if (!OSSL_PARAM_set_size_t(p, SIZE_MAX))
329                return 0;
330            break;
331        }
332    }
333    return 1;
334}
335
336static const OSSL_PARAM *kdf_scrypt_gettable_ctx_params(ossl_unused void *ctx,
337                                                        ossl_unused void *p_ctx)
338{
339    static const OSSL_PARAM known_gettable_ctx_params[] = {
340        OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
341        OSSL_PARAM_END
342    };
343    return known_gettable_ctx_params;
344}
345```
346