aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-12-16 11:41:45 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-01-20 15:27:45 +0900
commit0ec8143492cf1801bd210b52918da1b387510011 (patch)
tree0da7b710ffcd7ff2d4688006708d8bb6f0739e3b
parent5c586acc387834ab4e09260937dc21064fc59de4 (diff)
downloadruby-openssl-topic/pkey-dh-generate-key-length.tar.gz
pkey: allow specifying size of DH private exponent to generatetopic/pkey-dh-generate-key-length
Add an optional parameter to OpenSSL::PKey::DH#generate_key! that specifies the size in bits of the private exponent to generate. OpenSSL by default generates one with the maximum size: dh.p.num_bits-1. This is usually unnecessarily too large. Let user choose by their needs.
-rw-r--r--ext/openssl/openssl_missing.h2
-rw-r--r--ext/openssl/ossl_pkey_dh.c20
-rw-r--r--test/test_pkey_dh.rb7
3 files changed, 24 insertions, 5 deletions
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index cc31f6ac..ad7803dc 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -187,6 +187,8 @@ IMPL_PKEY_GETTER(DH, dh)
IMPL_KEY_ACCESSOR2(DH, key, pub_key, priv_key, (pub_key == obj->pub_key || (obj->priv_key && priv_key == obj->priv_key)))
IMPL_KEY_ACCESSOR3(DH, pqg, p, q, g, (p == obj->p || obj->q && q == obj->q || g == obj->g))
static inline ENGINE *DH_get0_engine(DH *dh) { return dh->engine; }
+static inline long DH_get_length(const DH *dh) { return dh->length; }
+static inline int DH_set_length(DH *dh, long length) { dh->length = length; return 1; }
#endif
#if !defined(OPENSSL_NO_EC)
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index dd85b7b9..de1dbf31 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -493,26 +493,36 @@ ossl_dh_check_params(VALUE self)
/*
* call-seq:
- * dh.generate_key! -> self
+ * dh.generate_key! -> self
+ * dh.generate_key!(length) -> self
*
- * Generates a private and public key unless a private key already exists.
+ * Generates a new random private and public exponent pair.
* If this DH instance was generated from public DH parameters (e.g. by
* encoding the result of DH#public_key), then this method needs to be
* called first in order to generate the per-session keys before performing
* the actual key exchange.
*
+ * If the optional parameter +length+ is given, a private exponent with that
+ * length (in bits) will be generated. This can be used to reduce calculation
+ * cost.
+ *
* === Example
* dh = OpenSSL::PKey::DH.new(2048)
- * public_key = dh.public_key #contains no private/public key yet
+ * public_key = dh.public_key # contains no private/public key yet
* public_key.generate_key!
* puts public_key.private? # => true
*/
static VALUE
-ossl_dh_generate_key(VALUE self)
+ossl_dh_generate_key(int argc, VALUE *argv, VALUE self)
{
DH *dh;
+ VALUE len_v;
+ long len;
+ rb_scan_args(argc, argv, "01", &len_v);
GetDH(self, dh);
+ len = NIL_P(len_v) ? 0 : NUM2LONG(len_v);
+ DH_set_length(dh, len);
if (!DH_generate_key(dh))
ossl_raise(eDHError, "Failed to generate key");
return self;
@@ -628,7 +638,7 @@ Init_ossl_dh(void)
rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
- rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
+ rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, -1);
rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
DEF_OSSL_PKEY_BN(cDH, dh, p);
diff --git a/test/test_pkey_dh.rb b/test/test_pkey_dh.rb
index 09a24279..bc6b722b 100644
--- a/test/test_pkey_dh.rb
+++ b/test/test_pkey_dh.rb
@@ -68,6 +68,13 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
assert_no_key(dh)
dh.generate_key!
assert_key(dh)
+ assert_equal(1024-1, dh.priv_key.num_bits)
+
+ dh = Fixtures.pkey_dh("dh1024").public_key # creates a copy
+ assert_no_key(dh)
+ dh.generate_key!(320)
+ assert_key(dh)
+ assert_equal(320, dh.priv_key.num_bits)
end
def test_key_exchange