@@ -423,6 +423,141 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
423423 return ossl_pkey_new (gen_arg .pkey );
424424}
425425
426+ #if OSSL_OPENSSL_PREREQ (3 , 0 , 0 )
427+ #include <openssl/param_build.h>
428+ #include <openssl/core_names.h>
429+
430+ static int
431+ add_ec_parameters_to_builder (VALUE key , VALUE value , VALUE arg ) {
432+ OSSL_PARAM_BLD * params_builder = (OSSL_PARAM_BLD * ) arg ;
433+
434+ if (NIL_P (value ))
435+ return ST_CONTINUE ;
436+
437+ if (SYMBOL_P (key ))
438+ key = rb_sym2str (key );
439+
440+ const char * key_ptr = StringValueCStr (key );
441+
442+ if (strcmp (OSSL_PKEY_PARAM_GROUP_NAME , key_ptr ) == 0 )
443+ if (!OSSL_PARAM_BLD_push_utf8_string (params_builder , key_ptr , StringValueCStr (value ), 0 ))
444+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_push_utf8_string" );
445+
446+ return ST_CONTINUE ;
447+ }
448+
449+ static int
450+ add_rsa_parameters_to_builder (VALUE key , VALUE value , VALUE arg ) {
451+ OSSL_PARAM_BLD * params_builder = (OSSL_PARAM_BLD * ) arg ;
452+
453+ if (NIL_P (value ))
454+ return ST_CONTINUE ;
455+
456+ if (SYMBOL_P (key ))
457+ key = rb_sym2str (key );
458+
459+ static const struct {
460+ char alias [5 ];
461+ char param_name [20 ];
462+ } key_aliases [] = {
463+ { "p" , OSSL_PKEY_PARAM_RSA_FACTOR1 },
464+ { "q" , OSSL_PKEY_PARAM_RSA_FACTOR2 },
465+ { "dmp1" , OSSL_PKEY_PARAM_RSA_EXPONENT1 },
466+ { "dmq1" , OSSL_PKEY_PARAM_RSA_EXPONENT2 },
467+ { "iqmp" , OSSL_PKEY_PARAM_RSA_COEFFICIENT1 }
468+ };
469+
470+ const char * key_ptr = StringValueCStr (key );
471+
472+ for (int i = 0 ; i < (int )(sizeof (key_aliases )/sizeof ((key_aliases )[0 ])); i ++ ) {
473+ if (strcmp (key_aliases [i ].alias , key_ptr ) == 0 ) {
474+ key_ptr = key_aliases [i ].param_name ;
475+ break ;
476+ }
477+ }
478+
479+ if ((strcmp (OSSL_PKEY_PARAM_RSA_N , key_ptr ) != 0 &&
480+ strcmp (OSSL_PKEY_PARAM_RSA_E , key_ptr ) != 0 &&
481+ strcmp (OSSL_PKEY_PARAM_RSA_D , key_ptr ) != 0 &&
482+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR1 , key_ptr ) != 0 &&
483+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR2 , key_ptr ) != 0 &&
484+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR3 , key_ptr ) != 0 &&
485+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR4 , key_ptr ) != 0 &&
486+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR5 , key_ptr ) != 0 &&
487+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR6 , key_ptr ) != 0 &&
488+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR7 , key_ptr ) != 0 &&
489+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR8 , key_ptr ) != 0 &&
490+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR9 , key_ptr ) != 0 &&
491+ strcmp (OSSL_PKEY_PARAM_RSA_FACTOR10 , key_ptr ) != 0 &&
492+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT1 , key_ptr ) != 0 &&
493+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT2 , key_ptr ) != 0 &&
494+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT3 , key_ptr ) != 0 &&
495+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT4 , key_ptr ) != 0 &&
496+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT5 , key_ptr ) != 0 &&
497+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT6 , key_ptr ) != 0 &&
498+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT7 , key_ptr ) != 0 &&
499+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT8 , key_ptr ) != 0 &&
500+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT9 , key_ptr ) != 0 &&
501+ strcmp (OSSL_PKEY_PARAM_RSA_EXPONENT10 , key_ptr ) != 0 &&
502+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT1 , key_ptr ) != 0 &&
503+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT2 , key_ptr ) != 0 &&
504+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT3 , key_ptr ) != 0 &&
505+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT4 , key_ptr ) != 0 &&
506+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT5 , key_ptr ) != 0 &&
507+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT6 , key_ptr ) != 0 &&
508+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT7 , key_ptr ) != 0 &&
509+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT8 , key_ptr ) != 0 &&
510+ strcmp (OSSL_PKEY_PARAM_RSA_COEFFICIENT9 , key_ptr )) != 0 )
511+ ossl_raise (ePKeyError , "Unsupported RSA parameter \"%s\"" , key_ptr );
512+
513+ if (!OSSL_PARAM_BLD_push_BN (params_builder , key_ptr , GetBNPtr (value )))
514+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_push_BN" );
515+
516+ return ST_CONTINUE ;
517+ }
518+
519+ static VALUE
520+ pkey_from_parameters (int argc , VALUE * argv , VALUE self )
521+ {
522+ VALUE alg , options ;
523+ rb_scan_args (argc , argv , "11" , & alg , & options );
524+
525+ OSSL_PARAM_BLD * params_builder = OSSL_PARAM_BLD_new ();
526+
527+ if (params_builder == NULL )
528+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_new" );
529+
530+ int (* param_adder )(VALUE , VALUE , VALUE ) = NULL ;
531+
532+ if (strcmp ("RSA" , StringValueCStr (alg )) == 0 )
533+ param_adder = & add_rsa_parameters_to_builder ;
534+ else if (strcmp ("EC" , StringValueCStr (alg )) == 0 )
535+ param_adder = & add_ec_parameters_to_builder ;
536+ else
537+ ossl_raise (ePKeyError , "\"%s\" is not a supported algorithm" , StringValueCStr (alg ));
538+
539+ rb_hash_foreach (options , param_adder , (VALUE ) params_builder );
540+
541+ OSSL_PARAM * params = OSSL_PARAM_BLD_to_param (params_builder );
542+ OSSL_PARAM_BLD_free (params_builder );
543+
544+ if (params == NULL )
545+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_to_param" );
546+
547+ EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new_from_name (NULL , StringValueCStr (alg ), NULL );
548+ EVP_PKEY * pkey = NULL ;
549+
550+ if (ctx == NULL ||
551+ EVP_PKEY_fromdata_init (ctx ) <= 0 ||
552+ EVP_PKEY_fromdata (ctx , & pkey , EVP_PKEY_KEYPAIR , params ) <= 0 ) {
553+ ossl_clear_error ();
554+ ossl_raise (ePKeyError , "EVP_PKEY_fromdata" );
555+ }
556+
557+ return ossl_pkey_new (pkey );
558+ }
559+ #endif
560+
426561/*
427562 * call-seq:
428563 * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
@@ -475,6 +610,17 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
475610 return pkey_generate (argc , argv , self , 0 );
476611}
477612
613+ static VALUE
614+ ossl_pkey_s_from_parameters (int argc , VALUE * argv , VALUE self )
615+ {
616+ // TODO: A version that works with OpenSSL 1.1
617+ #if OSSL_OPENSSL_PREREQ (3 , 0 , 0 )
618+ return pkey_from_parameters (argc , argv , self );
619+ #else
620+ rb_raise (ePKeyError , "Only supported with OpenSSL 3.0" );
621+ #endif
622+ }
623+
478624/*
479625 * TODO: There is no convenient way to check the presence of public key
480626 * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without
@@ -1586,6 +1732,7 @@ Init_ossl_pkey(void)
15861732 rb_define_module_function (mPKey , "read" , ossl_pkey_new_from_data , -1 );
15871733 rb_define_module_function (mPKey , "generate_parameters" , ossl_pkey_s_generate_parameters , -1 );
15881734 rb_define_module_function (mPKey , "generate_key" , ossl_pkey_s_generate_key , -1 );
1735+ rb_define_module_function (mPKey , "from_parameters" , ossl_pkey_s_from_parameters , -1 );
15891736
15901737 rb_define_alloc_func (cPKey , ossl_pkey_alloc );
15911738 rb_define_method (cPKey , "initialize" , ossl_pkey_initialize , 0 );
0 commit comments