@@ -446,6 +446,186 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
446
446
return ossl_pkey_new (gen_arg .pkey );
447
447
}
448
448
449
+ #if OSSL_OPENSSL_PREREQ (3 , 0 , 0 )
450
+ #include <openssl/param_build.h>
451
+ #include <openssl/core_names.h>
452
+
453
+ struct pkey_from_data_alias {
454
+ char alias [10 ];
455
+ char param_name [20 ];
456
+ };
457
+
458
+ static const struct pkey_from_data_alias rsa_aliases [] = {
459
+ { "p" , OSSL_PKEY_PARAM_RSA_FACTOR1 },
460
+ { "q" , OSSL_PKEY_PARAM_RSA_FACTOR2 },
461
+ { "dmp1" , OSSL_PKEY_PARAM_RSA_EXPONENT1 },
462
+ { "dmq1" , OSSL_PKEY_PARAM_RSA_EXPONENT2 },
463
+ { "iqmp" , OSSL_PKEY_PARAM_RSA_COEFFICIENT1 },
464
+ { "" , "" }
465
+ };
466
+
467
+ static const struct pkey_from_data_alias fcc_aliases [] = {
468
+ { "pub_key" , OSSL_PKEY_PARAM_PUB_KEY },
469
+ { "priv_key" , OSSL_PKEY_PARAM_PRIV_KEY },
470
+ { "" , "" }
471
+ };
472
+
473
+ struct pkey_from_data_arg {
474
+ VALUE options ;
475
+ OSSL_PARAM_BLD * param_bld ;
476
+ const OSSL_PARAM * settable_params ;
477
+ const struct pkey_from_data_alias * aliases ;
478
+ };
479
+
480
+ static int
481
+ add_data_to_builder (VALUE key , VALUE value , VALUE arg )
482
+ {
483
+ if (NIL_P (value ))
484
+ return ST_CONTINUE ;
485
+
486
+ if (SYMBOL_P (key ))
487
+ key = rb_sym2str (key );
488
+
489
+ const char * key_ptr = StringValueCStr (key );
490
+ const struct pkey_from_data_arg * params = (const struct pkey_from_data_arg * ) arg ;
491
+
492
+ for (int i = 0 ; strlen (params -> aliases [i ].alias ) > 0 ; i ++ ) {
493
+ if (strcmp (params -> aliases [i ].alias , key_ptr ) == 0 ) {
494
+ key_ptr = params -> aliases [i ].param_name ;
495
+ break ;
496
+ }
497
+ }
498
+
499
+ for (const OSSL_PARAM * settable_params = params -> settable_params ; settable_params -> key != NULL ; settable_params ++ ) {
500
+ if (strcmp (settable_params -> key , key_ptr ) == 0 ) {
501
+ switch (settable_params -> data_type ) {
502
+ case OSSL_PARAM_INTEGER :
503
+ case OSSL_PARAM_UNSIGNED_INTEGER :
504
+ if (!OSSL_PARAM_BLD_push_BN (params -> param_bld , key_ptr , GetBNPtr (value ))) {
505
+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_push_BN" );
506
+ }
507
+ break ;
508
+ case OSSL_PARAM_UTF8_STRING :
509
+ StringValue (value );
510
+ if (!OSSL_PARAM_BLD_push_utf8_string (params -> param_bld , key_ptr , RSTRING_PTR (value ), RSTRING_LENINT (value ))) {
511
+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_push_utf8_string" );
512
+ }
513
+ break ;
514
+
515
+ case OSSL_PARAM_OCTET_STRING :
516
+ StringValue (value );
517
+ if (!OSSL_PARAM_BLD_push_octet_string (params -> param_bld , key_ptr , RSTRING_PTR (value ), RSTRING_LENINT (value ))) {
518
+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_push_octet_string" );
519
+ }
520
+ break ;
521
+ case OSSL_PARAM_UTF8_PTR :
522
+ case OSSL_PARAM_OCTET_PTR :
523
+ ossl_raise (ePKeyError , "Unsupported parameter \"%s\", handling of OSSL_PARAM_UTF8_PTR and OSSL_PARAM_OCTET_PTR not implemented" , key_ptr );
524
+ break ;
525
+ default :
526
+ ossl_raise (ePKeyError , "Unsupported parameter \"%s\"" , key_ptr );
527
+ break ;
528
+ }
529
+
530
+ return ST_CONTINUE ;
531
+ }
532
+ }
533
+
534
+ VALUE supported_parameters = rb_ary_new ();
535
+
536
+ for (const OSSL_PARAM * settable_params = params -> settable_params ; settable_params -> key != NULL ; settable_params ++ ) {
537
+ rb_ary_push (supported_parameters , rb_str_new_cstr (settable_params -> key ));
538
+ }
539
+
540
+ for (int i = 0 ; strlen (params -> aliases [i ].alias ) > 0 ; i ++ ) {
541
+ rb_ary_push (supported_parameters , rb_str_new_cstr (params -> aliases [i ].alias ));
542
+ }
543
+
544
+ ossl_raise (ePKeyError , "Invalid parameter \"%s\". Supported parameters: %" PRIsVALUE , key_ptr , rb_ary_join (supported_parameters , rb_str_new2 (", " )));
545
+ }
546
+
547
+ static VALUE
548
+ iterate_from_data_options_cb (VALUE value )
549
+ {
550
+ struct pkey_from_data_arg * args = (void * )value ;
551
+
552
+ rb_hash_foreach (args -> options , & add_data_to_builder , (VALUE ) args );
553
+
554
+ return Qnil ;
555
+ }
556
+
557
+ static VALUE
558
+ pkey_from_data (int argc , VALUE * argv , VALUE self )
559
+ {
560
+ VALUE alg , options ;
561
+ rb_scan_args (argc , argv , "11" , & alg , & options );
562
+
563
+ const char * algorithm = StringValueCStr (alg );
564
+
565
+ EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new_from_name (NULL , algorithm , NULL );
566
+
567
+ if (ctx == NULL )
568
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_new_from_name" );
569
+
570
+ struct pkey_from_data_arg from_data_args = { 0 };
571
+
572
+ from_data_args .param_bld = OSSL_PARAM_BLD_new ();
573
+ from_data_args .options = options ;
574
+
575
+ if (from_data_args .param_bld == NULL ) {
576
+ EVP_PKEY_CTX_free (ctx );
577
+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_new" );
578
+ }
579
+
580
+ from_data_args .settable_params = EVP_PKEY_fromdata_settable (ctx , EVP_PKEY_KEYPAIR );
581
+
582
+ if (from_data_args .settable_params == NULL ) {
583
+ EVP_PKEY_CTX_free (ctx );
584
+ OSSL_PARAM_BLD_free (from_data_args .param_bld );
585
+ ossl_raise (ePKeyError , "EVP_PKEY_fromdata_settable" );
586
+ }
587
+
588
+ if (strcmp ("RSA" , algorithm ) == 0 )
589
+ from_data_args .aliases = rsa_aliases ;
590
+ else
591
+ from_data_args .aliases = fcc_aliases ;
592
+
593
+ int state ;
594
+ rb_protect (iterate_from_data_options_cb , (VALUE ) & from_data_args , & state );
595
+
596
+ if (state ) {
597
+ EVP_PKEY_CTX_free (ctx );
598
+ OSSL_PARAM_BLD_free (from_data_args .param_bld );
599
+ rb_jump_tag (state );
600
+ }
601
+
602
+ OSSL_PARAM * params = OSSL_PARAM_BLD_to_param (from_data_args .param_bld );
603
+ OSSL_PARAM_BLD_free (from_data_args .param_bld );
604
+
605
+ if (params == NULL ) {
606
+ EVP_PKEY_CTX_free (ctx );
607
+ ossl_raise (ePKeyError , "OSSL_PARAM_BLD_to_param" );
608
+ }
609
+
610
+ EVP_PKEY * pkey = NULL ;
611
+
612
+ if (EVP_PKEY_fromdata_init (ctx ) <= 0 ) {
613
+ EVP_PKEY_CTX_free (ctx );
614
+ ossl_raise (ePKeyError , "EVP_PKEY_fromdata_init" );
615
+ }
616
+
617
+ if (EVP_PKEY_fromdata (ctx , & pkey , EVP_PKEY_KEYPAIR , params ) <= 0 ) {
618
+ EVP_PKEY_CTX_free (ctx );
619
+ ossl_raise (ePKeyError , "EVP_PKEY_fromdata" );
620
+ }
621
+
622
+ EVP_PKEY_CTX_free (ctx );
623
+
624
+ return ossl_pkey_new (pkey );
625
+ }
626
+
627
+ #endif
628
+
449
629
/*
450
630
* call-seq:
451
631
* OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
@@ -498,6 +678,30 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
498
678
return pkey_generate (argc , argv , self , 0 );
499
679
}
500
680
681
+ /*
682
+ * call-seq:
683
+ * OpenSSL::PKey.from_data(algo_name, parameters) -> pkey
684
+ *
685
+ * Generates a new key based on given key parameters.
686
+ * NOTE: Requires OpenSSL 3.0 or later.
687
+ *
688
+ * The first parameter is the type of the key to create, given as a String, for example RSA, DSA, EC etc.
689
+ * Second parameter is the parameters to be used for the key.
690
+ *
691
+ * For details algorithms and parameters see https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_fromdata.html
692
+ *
693
+ * == Example
694
+ * pkey = OpenSSL::PKey.from_data("RSA", n: 3161751493, e: 65537, d: 2064855961)
695
+ * pkey.private? #=> true
696
+ * pkey.n #=> #<OpenSSL::BN 3161751493>
697
+ */
698
+ #if OSSL_OPENSSL_PREREQ (3 , 0 , 0 )
699
+ static VALUE
700
+ ossl_pkey_s_from_data (int argc , VALUE * argv , VALUE self )
701
+ {
702
+ return pkey_from_data (argc , argv , self );
703
+ }
704
+ #endif
501
705
/*
502
706
* TODO: There is no convenient way to check the presence of public key
503
707
* components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without
@@ -1751,6 +1955,9 @@ Init_ossl_pkey(void)
1751
1955
rb_define_module_function (mPKey , "read" , ossl_pkey_new_from_data , -1 );
1752
1956
rb_define_module_function (mPKey , "generate_parameters" , ossl_pkey_s_generate_parameters , -1 );
1753
1957
rb_define_module_function (mPKey , "generate_key" , ossl_pkey_s_generate_key , -1 );
1958
+ #if OSSL_OPENSSL_PREREQ (3 , 0 , 0 )
1959
+ rb_define_module_function (mPKey , "from_data" , ossl_pkey_s_from_data , -1 );
1960
+ #endif
1754
1961
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
1755
1962
rb_define_module_function (mPKey , "new_raw_private_key" , ossl_pkey_new_raw_private_key , 2 );
1756
1963
rb_define_module_function (mPKey , "new_raw_public_key" , ossl_pkey_new_raw_public_key , 2 );
0 commit comments