Skip to content

Commit 179c22c

Browse files
rheniumhsbt
authored andcommitted
pkey: from_data wip
1 parent fae71c4 commit 179c22c

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

ext/openssl/ossl_pkey.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
# include <openssl/engine.h>
1414
#endif
1515

16+
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
17+
# include <openssl/param_build.h>
18+
#endif
19+
1620
/*
1721
* Classes
1822
*/
@@ -180,6 +184,150 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
180184
return ossl_pkey_new(pkey);
181185
}
182186

187+
struct ossl_params_build_args {
188+
const OSSL_PARAM *settable;
189+
VALUE hash, *memo;
190+
OSSL_PARAM_BLD *param_bld;
191+
};
192+
193+
static int
194+
ossl_params_set_i(VALUE key, VALUE value, VALUE _args)
195+
{
196+
struct ossl_params_build_args *args = (void *)_args;
197+
const OSSL_PARAM *p;
198+
int ret;
199+
200+
if (SYMBOL_P(key))
201+
key = rb_sym2str(key);
202+
p = OSSL_PARAM_locate_const(args->settable, StringValueCStr(key));
203+
if (p == NULL)
204+
rb_raise(eOSSLError, "key not settable: %"PRIsVALUE, key);
205+
206+
switch (p->data_type) {
207+
case OSSL_PARAM_INTEGER:
208+
case OSSL_PARAM_UNSIGNED_INTEGER:
209+
ret = OSSL_PARAM_BLD_push_BN(args->param_bld, p->key,
210+
GetBNPtr(value));
211+
break;
212+
case OSSL_PARAM_UTF8_STRING:
213+
ret = OSSL_PARAM_BLD_push_utf8_string(args->param_bld, p->key,
214+
StringValueCStr(value),
215+
RSTRING_LEN(value));
216+
break;
217+
case OSSL_PARAM_OCTET_STRING:
218+
ret = OSSL_PARAM_BLD_push_octet_string(args->param_bld, p->key,
219+
StringValuePtr(value),
220+
RSTRING_LEN(value));
221+
break;
222+
case OSSL_PARAM_UTF8_PTR:
223+
ret = OSSL_PARAM_BLD_push_utf8_ptr(args->param_bld, p->key,
224+
StringValueCStr(value),
225+
RSTRING_LEN(value));
226+
if (*args->memo == Qundef)
227+
*args->memo = rb_ary_new();
228+
rb_ary_push(*args->memo, value);
229+
break;
230+
case OSSL_PARAM_OCTET_PTR:
231+
ret = OSSL_PARAM_BLD_push_utf8_ptr(args->param_bld, p->key,
232+
StringValuePtr(value),
233+
RSTRING_LEN(value));
234+
if (*args->memo == Qundef)
235+
*args->memo = rb_ary_new();
236+
rb_ary_push(*args->memo, value);
237+
break;
238+
default:
239+
rb_raise(eOSSLError, "unsupported data type %d for key %s",
240+
(int)p->data_type, p->key);
241+
}
242+
243+
if (ret <= 0)
244+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_push*");
245+
246+
return ST_CONTINUE;
247+
}
248+
249+
static VALUE
250+
ossl_params_build(VALUE _args)
251+
{
252+
struct ossl_params_build_args *args = (void *)_args;
253+
OSSL_PARAM *params;
254+
255+
args->param_bld = OSSL_PARAM_BLD_new();
256+
if (args->param_bld == NULL)
257+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_new");
258+
259+
rb_hash_foreach(args->hash, ossl_params_set_i, _args);
260+
261+
params = OSSL_PARAM_BLD_to_param(args->param_bld);
262+
if (!params)
263+
ossl_raise(eOSSLError, "OSSL_PARAM_BLD_to_params");
264+
265+
return (VALUE)params;
266+
}
267+
268+
static OSSL_PARAM *
269+
ossl_protect_params_build(const OSSL_PARAM *settable, VALUE hash,
270+
VALUE *memo, int *state)
271+
{
272+
struct ossl_params_build_args args;
273+
OSSL_PARAM *params;
274+
275+
args.settable = settable;
276+
args.hash = hash;
277+
args.memo = memo;
278+
279+
params = (void *)rb_protect(ossl_params_build, (VALUE)&args, state);
280+
OSSL_PARAM_BLD_free(args.param_bld);
281+
return params;
282+
}
283+
284+
/*
285+
* call-seq:
286+
* OpenSSL::PKey.from_data(algo, selection, hash) -> pkey
287+
*/
288+
static VALUE
289+
ossl_pkey_s_from_data(int argc, VALUE *argv, VALUE self)
290+
{
291+
VALUE type, vselection, hash, memo;
292+
const OSSL_PARAM *settable;
293+
OSSL_PARAM *params;
294+
EVP_PKEY_CTX *pctx;
295+
EVP_PKEY *pkey = NULL;
296+
int selection, state, ret;
297+
298+
rb_scan_args(argc, argv, "3", &type, &vselection, &hash);
299+
selection = NUM2INT(vselection);
300+
StringValueCStr(type);
301+
Check_Type(hash, T_HASH);
302+
303+
pctx = EVP_PKEY_CTX_new_from_name(NULL, RSTRING_PTR(type), NULL);
304+
if (!pctx)
305+
ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name");
306+
settable = EVP_PKEY_fromdata_settable(pctx, selection);
307+
if (!settable) {
308+
EVP_PKEY_CTX_free(pctx);
309+
ossl_raise(ePKeyError, "EVP_PKEY_fromdata_settable");
310+
}
311+
312+
params = ossl_protect_params_build(settable, hash, &memo, &state);
313+
if (state) {
314+
EVP_PKEY_CTX_free(pctx);
315+
rb_jump_tag(state);
316+
}
317+
318+
if (EVP_PKEY_fromdata_init(pctx) <= 0) {
319+
EVP_PKEY_CTX_free(pctx);
320+
ossl_raise(ePKeyError, "EVP_PKEY_fromdata_init");
321+
}
322+
ret = EVP_PKEY_fromdata(pctx, &pkey, selection, params);
323+
OSSL_PARAM_free(params);
324+
EVP_PKEY_CTX_free(pctx);
325+
326+
if (ret <= 0)
327+
ossl_raise(ePKeyError, "EVP_PKEY_fromdata");
328+
return ossl_pkey_new(pkey);
329+
}
330+
183331
static VALUE
184332
pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
185333
{
@@ -1687,6 +1835,7 @@ Init_ossl_pkey(void)
16871835
*/
16881836
cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
16891837

1838+
rb_define_module_function(mPKey, "from_data", ossl_pkey_s_from_data, -1);
16901839
rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
16911840
rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
16921841
rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
@@ -1718,6 +1867,10 @@ Init_ossl_pkey(void)
17181867
rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1);
17191868
rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1);
17201869

1870+
rb_define_const(mPKey, "KEY_PARAMETERS", INT2NUM(EVP_PKEY_KEY_PARAMETERS));
1871+
rb_define_const(mPKey, "PUBLIC_KEY", INT2NUM(EVP_PKEY_PUBLIC_KEY));
1872+
rb_define_const(mPKey, "KEYPAIR", INT2NUM(EVP_PKEY_KEYPAIR));
1873+
17211874
id_private_q = rb_intern("private?");
17221875

17231876
/*

test/openssl/test_pkey_rsa.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,12 @@ def test_to_data_public
583583
assert_equal nil, rsa.d
584584
end
585585

586+
def test_from_data
587+
pkey = Fixtures.pkey("rsa2048")
588+
589+
rsa1 = OpenSSL::PKey.from_data("RSA", OpenSSL::PKey::KEYPAIR, data)
590+
end
591+
586592
private
587593
def assert_same_rsa(expected, key)
588594
check_component(expected, key, [:n, :e, :d, :p, :q, :dmp1, :dmq1, :iqmp])

0 commit comments

Comments
 (0)