From a9c8efe196c079a634e11c8212313f63548529c6 Mon Sep 17 00:00:00 2001 From: rhe Date: Tue, 24 May 2016 16:30:15 +0000 Subject: openssl: add EC.generate * ext/openssl/ossl_pkey_ec.c (ec_key_new_from_group): Create a new EC_KEY on given EC group. Extracted from ossl_ec_key_initialize(). (ossl_ec_key_s_generate): Added. Create a new EC instance and generate a random private and public key. (ossl_ec_key_initialize): Use ec_key_new_from_group(). (Init_ossl_ec): Define the new method EC.generate. This change is for consistency with other PKey types. [ruby-core:45541] [Bug #6567] * test/openssl/test_pkey_ec.rb: Test that EC.generate works. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55152 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 12 ++++ ext/openssl/ossl_pkey_ec.c | 147 ++++++++++++++++++++++++++++--------------- test/openssl/test_pkey_ec.rb | 9 +++ 3 files changed, 117 insertions(+), 51 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6d9b83dd00..e8fa625051 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Wed May 25 01:13:55 2016 Kazuki Yamaguchi + + * ext/openssl/ossl_pkey_ec.c (ec_key_new_from_group): Create a new + EC_KEY on given EC group. Extracted from ossl_ec_key_initialize(). + (ossl_ec_key_s_generate): Added. Create a new EC instance and + generate a random private and public key. + (ossl_ec_key_initialize): Use ec_key_new_from_group(). + (Init_ossl_ec): Define the new method EC.generate. This change is + for consistency with other PKey types. [ruby-core:45541] [Bug #6567] + + * test/openssl/test_pkey_ec.rb: Test that EC.generate works. + Wed May 25 00:37:16 2016 Kazuki Yamaguchi * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_generate_key): Fix up RDoc. diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index 74bc7abea8..9210ae48ab 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -149,6 +149,69 @@ VALUE ossl_ec_new(EVP_PKEY *pkey) return obj; } +/* + * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String + * representing an OID. + */ +static EC_KEY * +ec_key_new_from_group(VALUE arg) +{ + EC_KEY *ec; + + if (rb_obj_is_kind_of(arg, cEC_GROUP)) { + EC_GROUP *group; + + SafeRequire_EC_GROUP(arg, group); + + if (!(ec = EC_KEY_new())) + ossl_raise(eECError, NULL); + + if (!EC_KEY_set_group(ec, group)) { + EC_KEY_free(ec); + ossl_raise(eECError, NULL); + } + } else { + int nid = OBJ_sn2nid(StringValueCStr(arg)); + + if (nid == NID_undef) + ossl_raise(eECError, "invalid curve name"); + + if (!(ec = EC_KEY_new_by_curve_name(nid))) + ossl_raise(eECError, NULL); + + EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); + } + + return ec; +} + +/* + * call-seq: + * EC.generate(ec_group) -> ec + * EC.generate(string) -> ec + * + * Creates a new EC instance with a new random private and public key. + */ +static VALUE +ossl_ec_key_s_generate(VALUE klass, VALUE arg) +{ + EC_KEY *ec; + VALUE obj; + + ec = ec_key_new_from_group(arg); + + obj = ec_instance(klass, ec); + if (obj == Qfalse) { + EC_KEY_free(ec); + ossl_raise(eECError, NULL); + } + + if (!EC_KEY_generate_key(ec)) + ossl_raise(eECError, "EC_KEY_generate_key"); + + return obj; +} /* call-seq: * OpenSSL::PKey::EC.new() @@ -165,9 +228,8 @@ VALUE ossl_ec_new(EVP_PKEY *pkey) static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; - EC_KEY *ec = NULL; + EC_KEY *ec; VALUE arg, pass; - VALUE group = Qnil; GetPKey(self, pkey); if (pkey->pkey.ec) @@ -176,58 +238,43 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "02", &arg, &pass); if (NIL_P(arg)) { - ec = EC_KEY_new(); + if (!(ec = EC_KEY_new())) + ossl_raise(eECError, NULL); + } else if (rb_obj_is_kind_of(arg, cEC)) { + EC_KEY *other_ec = NULL; + + SafeRequire_EC_KEY(arg, other_ec); + if (!(ec = EC_KEY_dup(other_ec))) + ossl_raise(eECError, NULL); + } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { + ec = ec_key_new_from_group(arg); } else { - if (rb_obj_is_kind_of(arg, cEC)) { - EC_KEY *other_ec = NULL; - - SafeRequire_EC_KEY(arg, other_ec); - ec = EC_KEY_dup(other_ec); - } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { - ec = EC_KEY_new(); - group = arg; - } else { - BIO *in; - - pass = ossl_pem_passwd_value(pass); - in = ossl_obj2bio(arg); - - ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); - if (!ec) { - OSSL_BIO_reset(in); - ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass); - } - if (!ec) { - OSSL_BIO_reset(in); - ec = d2i_ECPrivateKey_bio(in, NULL); - } - if (!ec) { - OSSL_BIO_reset(in); - ec = d2i_EC_PUBKEY_bio(in, NULL); - } - - BIO_free(in); - - if (ec == NULL) { - const char *name = StringValueCStr(arg); - int nid = OBJ_sn2nid(name); + BIO *in; - ossl_clear_error(); /* ignore errors in the previous d2i_EC_PUBKEY_bio() */ - if (nid == NID_undef) - ossl_raise(eECError, "unknown curve name (%"PRIsVALUE")", arg); + pass = ossl_pem_passwd_value(pass); + in = ossl_obj2bio(arg); - if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL) - ossl_raise(eECError, "unable to create curve (%"PRIsVALUE")\n", arg); + ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); + if (!ec) { + OSSL_BIO_reset(in); + ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass); + } + if (!ec) { + OSSL_BIO_reset(in); + ec = d2i_ECPrivateKey_bio(in, NULL); + } + if (!ec) { + OSSL_BIO_reset(in); + ec = d2i_EC_PUBKEY_bio(in, NULL); + } + BIO_free(in); - EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); - EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED); - } - } + if (!ec) { + ossl_clear_error(); + ec = ec_key_new_from_group(arg); + } } - if (ec == NULL) - ossl_raise(eECError, NULL); - if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { EC_KEY_free(ec); ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); @@ -235,9 +282,6 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) rb_iv_set(self, "@group", Qnil); - if (!NIL_P(group)) - rb_funcall(self, rb_intern("group="), 1, arg); - return self; } @@ -1620,6 +1664,7 @@ void Init_ossl_ec(void) rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0); + rb_define_singleton_method(cEC, "generate", ossl_ec_key_s_generate, 1); rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1); /* copy/dup/cmp */ diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 712507f609..4161e9b0e0 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -38,6 +38,15 @@ class OpenSSL::TestEC < OpenSSL::TestCase end end + def test_generate + assert_raise(OpenSSL::PKey::ECError) { OpenSSL::PKey::EC.generate("non-existent") } + g = OpenSSL::PKey::EC::Group.new("prime256v1") + ec = OpenSSL::PKey::EC.generate(g) + assert_equal(true, ec.private?) + ec = OpenSSL::PKey::EC.generate("prime256v1") + assert_equal(true, ec.private?) + end + def test_check_key for key in @keys assert_equal(true, key.check_key) -- cgit v1.2.3