summaryrefslogtreecommitdiff
path: root/ext/openssl/ossl_pkey_dh.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/openssl/ossl_pkey_dh.c')
-rw-r--r--ext/openssl/ossl_pkey_dh.c56
1 files changed, 51 insertions, 5 deletions
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 748d9c82fd..7f62db48d8 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -81,20 +81,66 @@ ossl_dh_new(EVP_PKEY *pkey)
/*
* Private
*/
+#if defined(HAVE_DH_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB
+struct dh_blocking_gen_arg {
+ DH *dh;
+ int size;
+ int gen;
+ BN_GENCB *cb;
+ int result;
+};
+
+static void
+dh_blocking_gen(void *arg)
+{
+ struct dh_blocking_gen_arg *gen = (struct dh_blocking_gen_arg *)arg;
+ gen->result = DH_generate_parameters_ex(gen->dh, gen->size, gen->gen, gen->cb);
+}
+#endif
+
static DH *
dh_generate(int size, int gen)
{
- DH *dh;
+#if defined(HAVE_DH_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB
+ BN_GENCB cb;
+ struct ossl_generate_cb_arg cb_arg;
+ struct dh_blocking_gen_arg gen_arg;
+ DH *dh = DH_new();
- dh = DH_generate_parameters(size, gen,
- rb_block_given_p() ? ossl_generate_cb : NULL,
- NULL);
if (!dh) return 0;
- if (!DH_generate_key(dh)) {
+ memset(&cb_arg, 0, sizeof(struct ossl_generate_cb_arg));
+ if (rb_block_given_p())
+ cb_arg.yield = 1;
+ BN_GENCB_set(&cb, ossl_generate_cb_2, &cb_arg);
+ gen_arg.dh = dh;
+ gen_arg.size = size;
+ gen_arg.gen = gen;
+ gen_arg.cb = &cb;
+ if (cb_arg.yield == 1) {
+ /* we cannot release GVL when callback proc is supplied */
+ dh_blocking_gen(&gen_arg);
+ } else {
+ /* there's a chance to unblock */
+ rb_thread_blocking_region(dh_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg);
+ }
+
+ if (!gen_arg.result) {
DH_free(dh);
+ if (cb_arg.state) rb_jump_tag(cb_arg.state);
return 0;
}
+#else
+ DH *dh;
+
+ dh = DH_generate_parameters(size, gen, rb_block_given_p() ? ossl_generate_cb : NULL, NULL);
+ if (!dh) return 0;
+#endif
+
+ if (!DH_generate_key(dh)) {
+ DH_free(dh);
+ return 0;
+ }
return dh;
}