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