diff options
author | Kazuki Yamaguchi <[email protected]> | 2020-05-17 22:14:03 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <[email protected]> | 2021-07-18 17:44:49 +0900 |
commit | 38436d1f5cb03520a2a4acca81f013de1c20daa5 (patch) | |
tree | af5e66a7cd3b46324d081fda18bd8b68e5e1741a | |
parent | b8dcf9c8fd7c093bfac003d6293315e2c9b1e46f (diff) |
[ruby/openssl] pkey/dsa: use high level EVP interface to generate parameters and keys
Implement PKey::DSA.new(size) and PKey::DSA.generate using
OpenSSL::PKey.generate_parameters and .generate_key instead of the low
level DSA functions.
https://github.com/ruby/openssl/commit/1800a8d5eb
-rw-r--r-- | ext/openssl/lib/openssl/pkey.rb | 30 | ||||
-rw-r--r-- | ext/openssl/ossl_pkey_dsa.c | 140 | ||||
-rw-r--r-- | test/openssl/test_pkey_dsa.rb | 23 |
3 files changed, 64 insertions, 129 deletions
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb index 3bef06e3b3..53ee52f98b 100644 --- a/ext/openssl/lib/openssl/pkey.rb +++ b/ext/openssl/lib/openssl/pkey.rb @@ -88,6 +88,36 @@ module OpenSSL::PKey class DSA include OpenSSL::Marshal + + class << self + # :call-seq: + # DSA.generate(size) -> dsa + # + # Creates a new DSA instance by generating a private/public key pair + # from scratch. + # + # See also OpenSSL::PKey.generate_parameters and + # OpenSSL::PKey.generate_key. + # + # +size+:: + # The desired key size in bits. + def generate(size, &blk) + dsaparams = OpenSSL::PKey.generate_parameters("DSA", { + "dsa_paramgen_bits" => size, + }, &blk) + OpenSSL::PKey.generate_key(dsaparams) + end + + # Handle DSA.new(size) form here; new(str) and new() forms + # are handled by #initialize + def new(*args, &blk) # :nodoc: + if args[0].is_a?(Integer) + generate(*args, &blk) + else + super + end + end + end end if defined?(EC) diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index 0e68f7f27f..1c5a8a737e 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -46,126 +46,39 @@ VALUE eDSAError; /* * Private */ -struct dsa_blocking_gen_arg { - DSA *dsa; - int size; - int *counter; - unsigned long *h; - BN_GENCB *cb; - int result; -}; - -static void * -dsa_blocking_gen(void *arg) -{ - struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg; - gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, NULL, 0, - gen->counter, gen->h, gen->cb); - return 0; -} - -static DSA * -dsa_generate(int size) -{ - struct ossl_generate_cb_arg cb_arg = { 0 }; - struct dsa_blocking_gen_arg gen_arg; - DSA *dsa = DSA_new(); - BN_GENCB *cb = BN_GENCB_new(); - int counter; - unsigned long h; - - if (!dsa || !cb) { - DSA_free(dsa); - BN_GENCB_free(cb); - ossl_raise(eDSAError, "malloc failure"); - } - - if (rb_block_given_p()) - cb_arg.yield = 1; - BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg); - gen_arg.dsa = dsa; - gen_arg.size = size; - gen_arg.counter = &counter; - gen_arg.h = &h; - gen_arg.cb = cb; - if (cb_arg.yield == 1) { - /* we cannot release GVL when callback proc is supplied */ - dsa_blocking_gen(&gen_arg); - } else { - /* there's a chance to unblock */ - rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); - } - - BN_GENCB_free(cb); - if (!gen_arg.result) { - DSA_free(dsa); - if (cb_arg.state) { - /* Clear OpenSSL error queue before re-raising. By the way, the - * documentation of DSA_generate_parameters_ex() says the error code - * can be obtained by ERR_get_error(), but the default - * implementation, dsa_builtin_paramgen() doesn't put any error... */ - ossl_clear_error(); - rb_jump_tag(cb_arg.state); - } - ossl_raise(eDSAError, "DSA_generate_parameters_ex"); - } - - if (!DSA_generate_key(dsa)) { - DSA_free(dsa); - ossl_raise(eDSAError, "DSA_generate_key"); - } - - return dsa; -} - -/* - * call-seq: - * DSA.generate(size) -> dsa - * - * Creates a new DSA instance by generating a private/public key pair - * from scratch. - * - * === Parameters - * * _size_ is an integer representing the desired key size. - * - */ -static VALUE -ossl_dsa_s_generate(VALUE klass, VALUE size) -{ - EVP_PKEY *pkey; - DSA *dsa; - VALUE obj; - - obj = rb_obj_alloc(klass); - GetPKey(obj, pkey); - - dsa = dsa_generate(NUM2INT(size)); - if (!EVP_PKEY_assign_DSA(pkey, dsa)) { - DSA_free(dsa); - ossl_raise(eDSAError, "EVP_PKEY_assign_DSA"); - } - return obj; -} - /* * call-seq: * DSA.new -> dsa - * DSA.new(size) -> dsa * DSA.new(string [, pass]) -> dsa + * DSA.new(size) -> dsa * * Creates a new DSA instance by reading an existing key from _string_. * - * === Parameters - * * _size_ is an integer representing the desired key size. - * * _string_ contains a DER or PEM encoded key. - * * _pass_ is a string that contains an optional password. + * If called without arguments, creates a new instance with no key components + * set. They can be set individually by #set_pqg and #set_key. * - * === Examples - * DSA.new -> dsa - * DSA.new(1024) -> dsa - * DSA.new(File.read('dsa.pem')) -> dsa - * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa + * If called with a String, tries to parse as DER or PEM encoding of a \DSA key. + * See also OpenSSL::PKey.read which can parse keys of any kinds. + * + * If called with a number, generates random parameters and a key pair. This + * form works as an alias of DSA.generate. + * + * +string+:: + * A String that contains a DER or PEM encoded key. + * +pass+:: + * A String that contains an optional password. + * +size+:: + * See DSA.generate. * + * Examples: + * p OpenSSL::PKey::DSA.new(1024) + * #=> #<OpenSSL::PKey::DSA:0x000055a8d6025bf0 oid=DSA> + * + * p OpenSSL::PKey::DSA.new(File.read('dsa.pem')) + * #=> #<OpenSSL::PKey::DSA:0x000055555d6b8110 oid=DSA> + * + * p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword') + * #=> #<OpenSSL::PKey::DSA:0x0000556f973c40b8 oid=DSA> */ static VALUE ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) @@ -176,15 +89,13 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) VALUE arg, pass; GetPKey(self, pkey); + /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */ rb_scan_args(argc, argv, "02", &arg, &pass); if (argc == 0) { dsa = DSA_new(); if (!dsa) ossl_raise(eDSAError, "DSA_new"); } - else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) { - dsa = dsa_generate(NUM2INT(arg)); - } else { pass = ossl_pem_passwd_value(pass); arg = ossl_to_der_if_possible(arg); @@ -553,7 +464,6 @@ Init_ossl_dsa(void) */ cDSA = rb_define_class_under(mPKey, "DSA", cPKey); - rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1); diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb index 4bf8a7b374..85bb6ec0ae 100644 --- a/test/openssl/test_pkey_dsa.rb +++ b/test/openssl/test_pkey_dsa.rb @@ -5,31 +5,26 @@ if defined?(OpenSSL) && defined?(OpenSSL::PKey::DSA) class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase def test_private - key = OpenSSL::PKey::DSA.new(256) - assert(key.private?) + key = Fixtures.pkey("dsa1024") + assert_equal true, key.private? key2 = OpenSSL::PKey::DSA.new(key.to_der) - assert(key2.private?) + assert_equal true, key2.private? key3 = key.public_key - assert(!key3.private?) + assert_equal false, key3.private? key4 = OpenSSL::PKey::DSA.new(key3.to_der) - assert(!key4.private?) + assert_equal false, key4.private? end def test_new - key = OpenSSL::PKey::DSA.new 256 + key = OpenSSL::PKey::DSA.new(2048) pem = key.public_key.to_pem OpenSSL::PKey::DSA.new pem - if $0 == __FILE__ - assert_nothing_raised { - key = OpenSSL::PKey::DSA.new 2048 - } - end end def test_new_break - assert_nil(OpenSSL::PKey::DSA.new(512) { break }) + assert_nil(OpenSSL::PKey::DSA.new(2048) { break }) assert_raise(RuntimeError) do - OpenSSL::PKey::DSA.new(512) { raise } + OpenSSL::PKey::DSA.new(2048) { raise } end end @@ -184,7 +179,7 @@ fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ== end def test_dup - key = OpenSSL::PKey::DSA.new(256) + key = Fixtures.pkey("dsa1024") key2 = key.dup assert_equal key.params, key2.params key2.set_pqg(key2.p + 1, key2.q, key2.g) |