@@ -771,6 +771,96 @@ ossl_pkey_inspect(VALUE self)
771771 return str ;
772772}
773773
774+ #ifdef HAVE_EVP_PKEY_GET_PARAMS
775+ /*
776+ * call-seq:
777+ * pkey.get_param(key) -> String or OpenSSL::BN
778+ *
779+ * Gets a parameter from the key. This is a low-level interface to OpenSSL's
780+ * EVP_PKEY_get_params() function, available in OpenSSL 3.0 or later.
781+ *
782+ * Check the relevant EVP_PKEY-* man page, or the documentation for the OpenSSL
783+ * provider in use, for the supported parameter keys and their return types.
784+ *
785+ * See the man page EVP_PKEY_get_params(3) for details.
786+ */
787+ static VALUE
788+ ossl_pkey_get_param (VALUE self , VALUE keyv )
789+ {
790+ EVP_PKEY * pkey ;
791+ const OSSL_PARAM * gettable_params , * p ;
792+ OSSL_PARAM params [] = {
793+ { NULL , 0 , NULL , 0 , OSSL_PARAM_UNMODIFIED },
794+ OSSL_PARAM_END ,
795+ };
796+ VALUE ret , tmp = 0 ;
797+
798+ GetPKey (self , pkey );
799+ gettable_params = EVP_PKEY_gettable_params (pkey );
800+ if (!gettable_params )
801+ ossl_raise (ePKeyError , "EVP_PKEY_gettable_params" );
802+ p = OSSL_PARAM_locate_const (gettable_params , StringValueCStr (keyv ));
803+ if (!p )
804+ ossl_raise (ePKeyError , "unrecognized OSSL_PARAM key: %" PRIsVALUE , keyv );
805+
806+ params [0 ].key = p -> key ;
807+ params [0 ].data_type = p -> data_type ;
808+ if (!EVP_PKEY_get_params (pkey , params ))
809+ ossl_raise (ePKeyError , "EVP_PKEY_get_params" );
810+ if (!OSSL_PARAM_modified (& params [0 ]))
811+ ossl_raise (ePKeyError , "OSSL_PARAM_modified" );
812+
813+ switch (p -> data_type ) {
814+ case OSSL_PARAM_INTEGER :
815+ case OSSL_PARAM_UNSIGNED_INTEGER :
816+ ret = ossl_bn_new (BN_value_one ());
817+ params [0 ].data_size =
818+ params [0 ].return_size > 0 ? params [0 ].return_size : 1 ;
819+ params [0 ].data = ALLOCV (tmp , params [0 ].data_size );
820+ break ;
821+ case OSSL_PARAM_UTF8_STRING :
822+ case OSSL_PARAM_OCTET_STRING :
823+ ret = rb_str_new (NULL , params [0 ].return_size );
824+ if (p -> data_type == OSSL_PARAM_UTF8_STRING )
825+ rb_enc_associate_index (ret , rb_utf8_encindex ());
826+ params [0 ].data_size = params [0 ].return_size ;
827+ params [0 ].data = RSTRING_PTR (ret );
828+ break ;
829+ default :
830+ /*
831+ * As of OpenSSL 4.0, the following data types are defined, but are
832+ * not actually used in EVP_PKEY_gettable_params(). So leave them
833+ * unimplemented for now:
834+ * - OSSL_PARAM_REAL (double)
835+ * - OSSL_PARAM_UTF8_PTR (C string)
836+ * - OSSL_PARAM_OCTET_PTR (arbitrary pointer?)
837+ */
838+ ossl_raise (ePKeyError , "unsupported OSSL_PARAM data type %d for key %s" ,
839+ p -> data_type , p -> key );
840+ }
841+ if (!EVP_PKEY_get_params (pkey , params ))
842+ ossl_raise (ePKeyError , "EVP_PKEY_get_params" );
843+
844+ switch (p -> data_type ) {
845+ case OSSL_PARAM_INTEGER :
846+ case OSSL_PARAM_UNSIGNED_INTEGER : {
847+ BIGNUM * bn = GetBNPtr (ret );
848+ if (!OSSL_PARAM_get_BN (& params [0 ], & bn ))
849+ ossl_raise (eOSSLError , "OSSL_PARAM_get_BN" );
850+ break ;
851+ }
852+ case OSSL_PARAM_UTF8_STRING :
853+ case OSSL_PARAM_OCTET_STRING :
854+ rb_str_set_len (ret , params [0 ].return_size );
855+ break ;
856+ }
857+ ALLOCV_END (tmp );
858+ return ret ;
859+ }
860+ #else
861+ #define ossl_pkey_get_param rb_f_notimplement
862+ #endif
863+
774864/*
775865 * call-seq:
776866 * pkey.to_text -> string
@@ -1868,6 +1958,7 @@ Init_ossl_pkey(void)
18681958#endif
18691959 rb_define_method (cPKey , "oid" , ossl_pkey_oid , 0 );
18701960 rb_define_method (cPKey , "inspect" , ossl_pkey_inspect , 0 );
1961+ rb_define_method (cPKey , "get_param" , ossl_pkey_get_param , 1 );
18711962 rb_define_method (cPKey , "to_text" , ossl_pkey_to_text , 0 );
18721963 rb_define_method (cPKey , "private_to_der" , ossl_pkey_private_to_der , -1 );
18731964 rb_define_method (cPKey , "private_to_pem" , ossl_pkey_private_to_pem , -1 );
0 commit comments