@@ -191,6 +191,226 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
191
191
return ossl_pkey_new (pkey );
192
192
}
193
193
194
+ static VALUE
195
+ pkey_gen_apply_options_i (RB_BLOCK_CALL_FUNC_ARGLIST (i , ctx_v ))
196
+ {
197
+ VALUE key = rb_ary_entry (i , 0 ), value = rb_ary_entry (i , 1 );
198
+ EVP_PKEY_CTX * ctx = (EVP_PKEY_CTX * )ctx_v ;
199
+
200
+ if (SYMBOL_P (key ))
201
+ key = rb_sym2str (key );
202
+ value = rb_String (value );
203
+
204
+ if (EVP_PKEY_CTX_ctrl_str (ctx , StringValueCStr (key ), StringValueCStr (value )) <= 0 )
205
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_ctrl_str(ctx, %+" PRIsVALUE ", %+" PRIsVALUE ")" ,
206
+ key , value );
207
+ return Qnil ;
208
+ }
209
+
210
+ static VALUE
211
+ pkey_gen_apply_options0 (VALUE args_v )
212
+ {
213
+ VALUE * args = (VALUE * )args_v ;
214
+
215
+ rb_block_call (args [1 ], rb_intern ("each" ), 0 , NULL ,
216
+ pkey_gen_apply_options_i , args [0 ]);
217
+ return Qnil ;
218
+ }
219
+
220
+ struct pkey_blocking_generate_arg {
221
+ EVP_PKEY_CTX * ctx ;
222
+ EVP_PKEY * pkey ;
223
+ int state ;
224
+ int yield : 1 ;
225
+ int genparam : 1 ;
226
+ int stop : 1 ;
227
+ };
228
+
229
+ static VALUE
230
+ pkey_gen_cb_yield (VALUE ctx_v )
231
+ {
232
+ EVP_PKEY_CTX * ctx = (void * )ctx_v ;
233
+ int i , info_num ;
234
+ VALUE * argv ;
235
+
236
+ info_num = EVP_PKEY_CTX_get_keygen_info (ctx , -1 );
237
+ argv = ALLOCA_N (VALUE , info_num );
238
+ for (i = 0 ; i < info_num ; i ++ )
239
+ argv [i ] = INT2NUM (EVP_PKEY_CTX_get_keygen_info (ctx , i ));
240
+
241
+ return rb_yield_values2 (info_num , argv );
242
+ }
243
+
244
+ static int
245
+ pkey_gen_cb (EVP_PKEY_CTX * ctx )
246
+ {
247
+ struct pkey_blocking_generate_arg * arg = EVP_PKEY_CTX_get_app_data (ctx );
248
+
249
+ if (arg -> yield ) {
250
+ int state ;
251
+ rb_protect (pkey_gen_cb_yield , (VALUE )ctx , & state );
252
+ if (state ) {
253
+ arg -> stop = 1 ;
254
+ arg -> state = state ;
255
+ }
256
+ }
257
+ return !arg -> stop ;
258
+ }
259
+
260
+ static void
261
+ pkey_blocking_gen_stop (void * ptr )
262
+ {
263
+ struct pkey_blocking_generate_arg * arg = ptr ;
264
+ arg -> stop = 1 ;
265
+ }
266
+
267
+ static void *
268
+ pkey_blocking_gen (void * ptr )
269
+ {
270
+ struct pkey_blocking_generate_arg * arg = ptr ;
271
+
272
+ if (arg -> genparam && EVP_PKEY_paramgen (arg -> ctx , & arg -> pkey ) <= 0 )
273
+ return NULL ;
274
+ if (!arg -> genparam && EVP_PKEY_keygen (arg -> ctx , & arg -> pkey ) <= 0 )
275
+ return NULL ;
276
+ return arg -> pkey ;
277
+ }
278
+
279
+ static VALUE
280
+ pkey_generate (int argc , VALUE * argv , VALUE self , int genparam )
281
+ {
282
+ EVP_PKEY_CTX * ctx ;
283
+ VALUE alg , options ;
284
+ struct pkey_blocking_generate_arg gen_arg = { 0 };
285
+ int state ;
286
+
287
+ rb_scan_args (argc , argv , "11" , & alg , & options );
288
+ if (rb_obj_is_kind_of (alg , cPKey )) {
289
+ EVP_PKEY * base_pkey ;
290
+
291
+ GetPKey (alg , base_pkey );
292
+ ctx = EVP_PKEY_CTX_new (base_pkey , NULL /* engine */ );
293
+ if (!ctx )
294
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_new" );
295
+ }
296
+ else {
297
+ const EVP_PKEY_ASN1_METHOD * ameth ;
298
+ ENGINE * tmpeng ;
299
+ int pkey_id ;
300
+
301
+ StringValue (alg );
302
+ ameth = EVP_PKEY_asn1_find_str (& tmpeng , RSTRING_PTR (alg ),
303
+ RSTRING_LENINT (alg ));
304
+ if (!ameth )
305
+ ossl_raise (ePKeyError , "algorithm %" PRIsVALUE " not found" , alg );
306
+ EVP_PKEY_asn1_get0_info (& pkey_id , NULL , NULL , NULL , NULL , ameth );
307
+ #if !defined(OPENSSL_NO_ENGINE )
308
+ if (tmpeng )
309
+ ENGINE_finish (tmpeng );
310
+ #endif
311
+
312
+ ctx = EVP_PKEY_CTX_new_id (pkey_id , NULL /* engine */ );
313
+ if (!ctx )
314
+ ossl_raise (ePKeyError , "EVP_PKEY_CTX_new_id" );
315
+ }
316
+
317
+ if (genparam && EVP_PKEY_paramgen_init (ctx ) <= 0 ) {
318
+ EVP_PKEY_CTX_free (ctx );
319
+ ossl_raise (ePKeyError , "EVP_PKEY_paramgen_init" );
320
+ }
321
+ if (!genparam && EVP_PKEY_keygen_init (ctx ) <= 0 ) {
322
+ EVP_PKEY_CTX_free (ctx );
323
+ ossl_raise (ePKeyError , "EVP_PKEY_keygen_init" );
324
+ }
325
+
326
+ if (!NIL_P (options )) {
327
+ VALUE args [2 ];
328
+
329
+ args [0 ] = (VALUE )ctx ;
330
+ args [1 ] = options ;
331
+ rb_protect (pkey_gen_apply_options0 , (VALUE )args , & state );
332
+ if (state ) {
333
+ EVP_PKEY_CTX_free (ctx );
334
+ rb_jump_tag (state );
335
+ }
336
+ }
337
+
338
+ gen_arg .genparam = genparam ;
339
+ gen_arg .ctx = ctx ;
340
+ gen_arg .yield = rb_block_given_p ();
341
+ EVP_PKEY_CTX_set_app_data (ctx , & gen_arg );
342
+ EVP_PKEY_CTX_set_cb (ctx , pkey_gen_cb );
343
+ if (gen_arg .yield )
344
+ pkey_blocking_gen (& gen_arg );
345
+ else
346
+ rb_thread_call_without_gvl (pkey_blocking_gen , & gen_arg ,
347
+ pkey_blocking_gen_stop , & gen_arg );
348
+ EVP_PKEY_CTX_free (ctx );
349
+ if (!gen_arg .pkey ) {
350
+ if (gen_arg .state ) {
351
+ ossl_clear_error ();
352
+ rb_jump_tag (gen_arg .state );
353
+ }
354
+ else {
355
+ ossl_raise (ePKeyError , genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen" );
356
+ }
357
+ }
358
+
359
+ return ossl_pkey_new (gen_arg .pkey );
360
+ }
361
+
362
+ /*
363
+ * call-seq:
364
+ * OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
365
+ *
366
+ * Generates new parameters for the algorithm. _algo_name_ is a String that
367
+ * represents the algorithm. The optional argument _options_ is a Hash that
368
+ * specifies the options specific to the algorithm. The order of the options
369
+ * can be important.
370
+ *
371
+ * A block can be passed optionally. The meaning of the arguments passed to
372
+ * the block varies depending on the implementation of the algorithm. The block
373
+ * may be called once or multiple times, or may not even be called.
374
+ *
375
+ * For the supported options, see the documentation for the 'openssl genpkey'
376
+ * utility command.
377
+ *
378
+ * == Example
379
+ * pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
380
+ * p pkey.p.num_bits #=> 2048
381
+ */
382
+ static VALUE
383
+ ossl_pkey_s_generate_parameters (int argc , VALUE * argv , VALUE self )
384
+ {
385
+ return pkey_generate (argc , argv , self , 1 );
386
+ }
387
+
388
+ /*
389
+ * call-seq:
390
+ * OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey
391
+ * OpenSSL::PKey.generate_key(pkey [, options]) -> pkey
392
+ *
393
+ * Generates a new key (pair).
394
+ *
395
+ * If a String is given as the first argument, it generates a new random key
396
+ * for the algorithm specified by the name just as ::generate_parameters does.
397
+ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key
398
+ * for the same algorithm as the key, using the parameters the key contains.
399
+ *
400
+ * See ::generate_parameters for the details of _options_ and the given block.
401
+ *
402
+ * == Example
403
+ * pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
404
+ * pkey_params.priv_key #=> nil
405
+ * pkey = OpenSSL::PKey.generate_key(pkey_params)
406
+ * pkey.priv_key #=> #<OpenSSL::BN 6277...
407
+ */
408
+ static VALUE
409
+ ossl_pkey_s_generate_key (int argc , VALUE * argv , VALUE self )
410
+ {
411
+ return pkey_generate (argc , argv , self , 0 );
412
+ }
413
+
194
414
void
195
415
ossl_pkey_check_public_key (const EVP_PKEY * pkey )
196
416
{
@@ -655,6 +875,8 @@ Init_ossl_pkey(void)
655
875
cPKey = rb_define_class_under (mPKey , "PKey" , rb_cObject );
656
876
657
877
rb_define_module_function (mPKey , "read" , ossl_pkey_new_from_data , -1 );
878
+ rb_define_module_function (mPKey , "generate_parameters" , ossl_pkey_s_generate_parameters , -1 );
879
+ rb_define_module_function (mPKey , "generate_key" , ossl_pkey_s_generate_key , -1 );
658
880
659
881
rb_define_alloc_func (cPKey , ossl_pkey_alloc );
660
882
rb_define_method (cPKey , "initialize" , ossl_pkey_initialize , 0 );
0 commit comments