Skip to content

Commit c9d0322

Browse files
committed
ossl.c: add ossl_build_params()
Provide a useful function to make a heap-allocated array of OSSL_PARAM from Enumerable. OSSL_PARAM is a new type added in OpenSSL 3.0 and used by various new APIs for taking arbitrary parameters. The next patch will use this with EVP_KDF to implement OpenSSL::KDF.derive.
1 parent eb39987 commit c9d0322

File tree

4 files changed

+121
-4
lines changed

4 files changed

+121
-4
lines changed

ext/openssl/ossl.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,114 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)
217217
return (int)len;
218218
}
219219

220+
#ifdef OSSL_PARAM_INTEGER
221+
#include <openssl/param_build.h>
222+
223+
struct build_params_args {
224+
const OSSL_PARAM *settable;
225+
VALUE hash;
226+
OSSL_PARAM_BLD *bld;
227+
};
228+
229+
static VALUE
230+
build_params_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo))
231+
{
232+
struct build_params_args *args = (struct build_params_args *)memo;
233+
VALUE keyv = rb_ary_entry(i, 0), obj = rb_ary_entry(i, 1);
234+
OSSL_PARAM_BLD *bld = args->bld;
235+
236+
if (SYMBOL_P(keyv))
237+
keyv = rb_sym2str(keyv);
238+
239+
const OSSL_PARAM *p = args->settable;
240+
const char *key = StringValueCStr(keyv);
241+
while (p->key && strcmp(p->key, key))
242+
p++;
243+
if (!p->key)
244+
rb_raise(rb_eArgError, "unknown OSSL_PARAM key '%"PRIsVALUE"'", keyv);
245+
246+
switch (p->data_type) {
247+
case OSSL_PARAM_INTEGER:
248+
case OSSL_PARAM_UNSIGNED_INTEGER:
249+
obj = ossl_try_convert_to_bn(obj);
250+
if (NIL_P(obj))
251+
rb_raise(rb_eArgError, "OSSL_PARAM key '%s' requires " \
252+
"integer value", p->key);
253+
const BIGNUM *bn = GetBNPtr(obj);
254+
if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER && BN_is_negative(bn))
255+
rb_raise(rb_eArgError, "OSSL_PARAM key '%s' requires " \
256+
"non-negative integer value", p->key);
257+
if (!OSSL_PARAM_BLD_push_BN(bld, p->key, GetBNPtr(obj)))
258+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_push_BN");
259+
break;
260+
case OSSL_PARAM_REAL:
261+
obj = rb_check_to_float(obj);
262+
if (NIL_P(obj))
263+
rb_raise(rb_eArgError, "OSSL_PARAM key '%s' requires Float value",
264+
p->key);
265+
if (!OSSL_PARAM_BLD_push_double(bld, p->key, NUM2DBL(obj)))
266+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_push_double");
267+
break;
268+
case OSSL_PARAM_UTF8_STRING:
269+
obj = rb_check_string_type(obj);
270+
if (NIL_P(obj))
271+
rb_raise(rb_eArgError, "OSSL_PARAM key '%s' requires " \
272+
"NUL-terminated String value", p->key);
273+
StringValueCStr(obj);
274+
if (!OSSL_PARAM_BLD_push_utf8_string(bld, p->key, RSTRING_PTR(obj),
275+
RSTRING_LEN(obj)))
276+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_push_utf8_string");
277+
break;
278+
case OSSL_PARAM_OCTET_STRING:
279+
obj = rb_check_string_type(obj);
280+
if (NIL_P(obj))
281+
rb_raise(rb_eArgError, "OSSL_PARAM key '%s' requires String value",
282+
p->key);
283+
if (!OSSL_PARAM_BLD_push_octet_string(bld, p->key, RSTRING_PTR(obj),
284+
RSTRING_LEN(obj)))
285+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_push_octet_string");
286+
break;
287+
default:
288+
/*
289+
* Types not used in settable OSSL_PARAMs as of OpenSSL 3.5:
290+
* - OSSL_PARAM_UTF8_PTR
291+
* - OSSL_PARAM_OCTET_PTR
292+
*/
293+
rb_raise(eOSSLError, "unsupported type %d for OSSL_PARAM key '%s'",
294+
p->data_type, p->key);
295+
}
296+
return Qnil;
297+
}
298+
299+
static VALUE
300+
build_params_internal(VALUE memo)
301+
{
302+
struct build_params_args *args = (struct build_params_args *)memo;
303+
304+
args->bld = OSSL_PARAM_BLD_new();
305+
if (!args->bld)
306+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_new");
307+
308+
if (!NIL_P(args->hash))
309+
rb_block_call(args->hash, rb_intern("each"), 0, NULL, build_params_i,
310+
(VALUE)args);
311+
312+
OSSL_PARAM *ret = OSSL_PARAM_BLD_to_param(args->bld);
313+
if (!ret)
314+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_to_param");
315+
return (VALUE)ret;
316+
}
317+
318+
OSSL_PARAM *
319+
ossl_build_params(const OSSL_PARAM *settable, VALUE hash, int *state)
320+
{
321+
struct build_params_args args = { settable, hash, NULL };
322+
VALUE params = rb_protect(build_params_internal, (VALUE)&args, state);
323+
OSSL_PARAM_BLD_free(args.bld);
324+
return (OSSL_PARAM *)params;
325+
}
326+
#endif
327+
220328
/*
221329
* main module
222330
*/

ext/openssl/ossl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ void ossl_clear_error(void);
164164
VALUE ossl_to_der(VALUE);
165165
VALUE ossl_to_der_if_possible(VALUE);
166166

167+
#ifdef OSSL_PARAM_INTEGER
168+
/*
169+
* Build OSSL_PARAM array from Hash/Enumerable. The OSSL_PARAM array is
170+
* allocated by OpenSSL, so it must be freed by OSSL_PARAM_free() after use.
171+
*/
172+
OSSL_PARAM *ossl_build_params(const OSSL_PARAM *settable, VALUE hash, int *state);
173+
#endif
174+
167175
/*
168176
* Debug
169177
*/

ext/openssl/ossl_bn.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ integer_to_bnptr(VALUE obj, BIGNUM *orig)
115115
return bn;
116116
}
117117

118-
static VALUE
119-
try_convert_to_bn(VALUE obj)
118+
VALUE
119+
ossl_try_convert_to_bn(VALUE obj)
120120
{
121121
BIGNUM *bn;
122122
VALUE newobj = Qnil;
@@ -138,7 +138,7 @@ ossl_bn_value_ptr(volatile VALUE *ptr)
138138
VALUE tmp;
139139
BIGNUM *bn;
140140

141-
tmp = try_convert_to_bn(*ptr);
141+
tmp = ossl_try_convert_to_bn(*ptr);
142142
if (NIL_P(tmp))
143143
ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
144144
GetBN(tmp, bn);
@@ -1048,7 +1048,7 @@ ossl_bn_eq(VALUE self, VALUE other)
10481048
BIGNUM *bn1, *bn2;
10491049

10501050
GetBN(self, bn1);
1051-
other = try_convert_to_bn(other);
1051+
other = ossl_try_convert_to_bn(other);
10521052
if (NIL_P(other))
10531053
return Qfalse;
10541054
GetBN(other, bn2);

ext/openssl/ossl_bn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ BN_CTX *ossl_bn_ctx_get(void);
1818
#define GetBNPtr(obj) ossl_bn_value_ptr(&(obj))
1919

2020
VALUE ossl_bn_new(const BIGNUM *);
21+
VALUE ossl_try_convert_to_bn(VALUE obj);
2122
BIGNUM *ossl_bn_value_ptr(volatile VALUE *);
2223
void Init_ossl_bn(void);
2324

0 commit comments

Comments
 (0)