From 14db82192b9f59d2015b72afee4a73cac64d8aa5 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 29 Oct 2023 10:54:36 +0800 Subject: [PATCH 1/8] Adding utility to return the actual bit size of the key. Especially needed for key such as X25519 where the size not in byte boundary --- ext/openssl/ossl_pkey.c | 20 ++++++++++++++++++++ test/openssl/test_pkey.rb | 1 + test/openssl/test_pkey_dh.rb | 3 +++ test/openssl/test_pkey_ec.rb | 3 +++ 4 files changed, 27 insertions(+) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 013412c27..b49aa50ba 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -1666,6 +1666,23 @@ ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) return str; } + +/* + * Returns bit length of the PKEy + */ +static VALUE +ossl_pkey_length_in_bits(VALUE self) +{ + EVP_PKEY * pkey; + int bits; + + GetPKey(self, pkey); + + bits = EVP_PKEY_get_bits(pkey); + return INT2NUM(bits); + +} + /* * INIT */ @@ -1785,6 +1802,9 @@ Init_ossl_pkey(void) rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); + + rb_define_method(cPKey, "keysize_in_bits", ossl_pkey_length_in_bits, 0); + id_private_q = rb_intern("private?"); /* diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index aee0546f6..d8f18cf1d 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -24,6 +24,7 @@ def test_generic_oid_inspect assert_instance_of OpenSSL::PKey::PKey, x25519 assert_equal "X25519", x25519.oid assert_match %r{oid=X25519}, x25519.inspect + assert_equal 253, x25519.keysize_in_bits end def test_s_generate_parameters diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb index 161af1897..5fe8e5221 100644 --- a/test/openssl/test_pkey_dh.rb +++ b/test/openssl/test_pkey_dh.rb @@ -36,6 +36,9 @@ def test_derive_key assert_equal z, dh1.derive(dh2_pub) assert_equal z, dh2.derive(dh1_pub) + assert_equal(1024, dh1.keysize_in_bits) + assert_equal(1024, dh2.keysize_in_bits) + assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) } assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) } diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 2cb8e287a..51fa3de76 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -76,16 +76,19 @@ def test_check_key assert_equal(true, key0.check_key) assert_equal(true, key0.private?) assert_equal(true, key0.public?) + assert_equal(256, key0.keysize_in_bits) key1 = OpenSSL::PKey.read(key0.public_to_der) assert_equal(true, key1.check_key) assert_equal(false, key1.private?) assert_equal(true, key1.public?) + assert_equal(256, key1.keysize_in_bits) key2 = OpenSSL::PKey.read(key0.private_to_der) assert_equal(true, key2.private?) assert_equal(true, key2.public?) assert_equal(true, key2.check_key) + assert_equal(256, key2.keysize_in_bits) # Behavior of EVP_PKEY_public_check changes between OpenSSL 1.1.1 and 3.0 key4 = Fixtures.pkey("p256_too_large") From 7ff37378ae9e2ff6968cbe3939d6ff28c253c8da Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 13 Nov 2023 16:55:24 +0800 Subject: [PATCH 2/8] Reformat the source code and create new test cases for keysize_in_bits --- ext/openssl/ossl_pkey.c | 43 +++++++++++++++++++----------- test/openssl/test_pkey.rb | 51 +++++++++++++++++++++++++++++++++++- test/openssl/test_pkey_dh.rb | 3 --- test/openssl/test_pkey_ec.rb | 26 ++++++++++++++++++ 4 files changed, 103 insertions(+), 20 deletions(-) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index b49aa50ba..7f622b227 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -737,6 +737,32 @@ ossl_pkey_inspect(VALUE self) OBJ_nid2sn(nid)); } +/* + * call-seq: + * pkey.keysize_in_bits -> integer + * + * Returns an integer representing cryptographic length of the cryptosystem to which the key + * in _pkey_ belongs, in bits. + * + * See man page EVP_PKEY_get_bits(3) + */ +static VALUE +ossl_pkey_length_in_bits(VALUE self) +{ + EVP_PKEY * pkey; + int bits; + + GetPKey(self, pkey); + +#if OSSL_OPENSSL_PREREQ(3, 0, 0) + bits = EVP_PKEY_get_bits(pkey); +#else + bits = EVP_PKEY_bits(pkey); +#endif + return INT2NUM(bits); + +} + /* * call-seq: * pkey.to_text -> string @@ -1667,21 +1693,6 @@ ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) } -/* - * Returns bit length of the PKEy - */ -static VALUE -ossl_pkey_length_in_bits(VALUE self) -{ - EVP_PKEY * pkey; - int bits; - - GetPKey(self, pkey); - - bits = EVP_PKEY_get_bits(pkey); - return INT2NUM(bits); - -} /* * INIT @@ -1782,6 +1793,7 @@ Init_ossl_pkey(void) #endif rb_define_method(cPKey, "oid", ossl_pkey_oid, 0); rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0); + rb_define_method(cPKey, "keysize_in_bits", ossl_pkey_length_in_bits, 0); rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0); rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1); rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1); @@ -1803,7 +1815,6 @@ Init_ossl_pkey(void) rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); - rb_define_method(cPKey, "keysize_in_bits", ossl_pkey_length_in_bits, 0); id_private_q = rb_intern("private?"); diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index d8f18cf1d..a3e519bee 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -24,7 +24,6 @@ def test_generic_oid_inspect assert_instance_of OpenSSL::PKey::PKey, x25519 assert_equal "X25519", x25519.oid assert_match %r{oid=X25519}, x25519.inspect - assert_equal 253, x25519.keysize_in_bits end def test_s_generate_parameters @@ -245,4 +244,54 @@ def test_to_text rsa = Fixtures.pkey("rsa1024") assert_include rsa.to_text, "publicExponent" end + + def test_keysize_in_bits + # Test vector from RFC 7748 Section 6.1 + alice_pem = <<~EOF + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq + -----END PRIVATE KEY----- + EOF + bob_pem = <<~EOF + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= + -----END PUBLIC KEY----- + EOF + begin + alice = OpenSSL::PKey.read(alice_pem) + bob = OpenSSL::PKey.read(bob_pem) + + assert_equal 253, alice.keysize_in_bits + assert_equal 253, bob.keysize_in_bits + + rescue OpenSSL::PKey::PKeyError + # OpenSSL < 1.1.0 + pend "X25519 is not implemented" + end + + # Test vector from RFC 8032 Section 7.1 TEST 2 + priv_pem = <<~EOF + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 + -----END PRIVATE KEY----- + EOF + pub_pem = <<~EOF + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= + -----END PUBLIC KEY----- + EOF + begin + priv = OpenSSL::PKey.read(priv_pem) + pub = OpenSSL::PKey.read(pub_pem) + + assert_equal 256, priv.keysize_in_bits + assert_equal 256, pub.keysize_in_bits + + rescue OpenSSL::PKey::PKeyError => e + # OpenSSL < 1.1.1 + pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) + end + + end + end diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb index 5fe8e5221..161af1897 100644 --- a/test/openssl/test_pkey_dh.rb +++ b/test/openssl/test_pkey_dh.rb @@ -36,9 +36,6 @@ def test_derive_key assert_equal z, dh1.derive(dh2_pub) assert_equal z, dh2.derive(dh1_pub) - assert_equal(1024, dh1.keysize_in_bits) - assert_equal(1024, dh2.keysize_in_bits) - assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) } assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) } diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 51fa3de76..52280b7c2 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -71,6 +71,32 @@ def test_marshal assert_equal key.to_der, deserialized.to_der end + def test_keysize_in_bits + OpenSSL::PKey::EC.builtin_curves.map { |name, comment| name }.each do |curve| + if !openssl?(3, 0, 0) + ec = OpenSSL::PKey::EC.new(curve) + ec.generate_key! + else + ec = OpenSSL::PKey::EC.generate(curve) + end + + case curve + when "secp224r1" + assert_equal(224, ec.keysize_in_bits) + when "secp256r1", "brainpoolP256r1", "brainpoolP256t1", "prime256v1" + assert_equal(256, ec.keysize_in_bits) + when "secp384r1", "brainpoolP384r1", "brainpoolP384t1" + assert_equal(384, ec.keysize_in_bits) + when "secp521r1" + assert_equal(521, ec.keysize_in_bits) + when "brainpoolP512r1", "brainpoolP512t1" + assert_equal(512, ec.keysize_in_bits) + when "brainpoolP320r1", "brainpoolP320t1" + assert_equal(320, ec.keysize_in_bits) + end + end + end + def test_check_key key0 = Fixtures.pkey("p256") assert_equal(true, key0.check_key) From b92ee8bdf064e7229f12776a037375d9ebdda9f5 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 13 Nov 2023 17:00:58 +0800 Subject: [PATCH 3/8] Missed one place to in test case ec --- test/openssl/test_pkey_ec.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 52280b7c2..b2f2304a9 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -102,19 +102,16 @@ def test_check_key assert_equal(true, key0.check_key) assert_equal(true, key0.private?) assert_equal(true, key0.public?) - assert_equal(256, key0.keysize_in_bits) key1 = OpenSSL::PKey.read(key0.public_to_der) assert_equal(true, key1.check_key) assert_equal(false, key1.private?) assert_equal(true, key1.public?) - assert_equal(256, key1.keysize_in_bits) key2 = OpenSSL::PKey.read(key0.private_to_der) assert_equal(true, key2.private?) assert_equal(true, key2.public?) assert_equal(true, key2.check_key) - assert_equal(256, key2.keysize_in_bits) # Behavior of EVP_PKEY_public_check changes between OpenSSL 1.1.1 and 3.0 key4 = Fixtures.pkey("p256_too_large") From 0b3fe97673826874ff1469f794df253545313992 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 14 Nov 2023 11:35:29 +0800 Subject: [PATCH 4/8] Seems the reporting of keysize is not consistent across different OpenSSL versions. Also the spec seems only specified the key length of public key, no mention of private key size --- test/openssl/test_pkey.rb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index a3e519bee..d749f81d2 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -270,21 +270,14 @@ def test_keysize_in_bits end # Test vector from RFC 8032 Section 7.1 TEST 2 - priv_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 - -----END PRIVATE KEY----- - EOF pub_pem = <<~EOF -----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= -----END PUBLIC KEY----- EOF begin - priv = OpenSSL::PKey.read(priv_pem) + pub = OpenSSL::PKey.read(pub_pem) - - assert_equal 256, priv.keysize_in_bits assert_equal 256, pub.keysize_in_bits rescue OpenSSL::PKey::PKeyError => e From 370b2f1a7bea1aeb7db0a65e6344717e4a007459 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 14 Nov 2023 17:39:49 +0800 Subject: [PATCH 5/8] Add condition to test keysize in bits since OpenSSL version 1.1.1 returns different value then the rest of the versions --- test/openssl/test_pkey.rb | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index d749f81d2..0bd41ceaa 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -270,15 +270,31 @@ def test_keysize_in_bits end # Test vector from RFC 8032 Section 7.1 TEST 2 + priv_pem = <<~EOF + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 + -----END PRIVATE KEY----- + EOF pub_pem = <<~EOF -----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= -----END PUBLIC KEY----- EOF begin - + priv = OpenSSL::PKey.read(priv_pem) pub = OpenSSL::PKey.read(pub_pem) - assert_equal 256, pub.keysize_in_bits + + if openssl?(1,1,1) + # for some reason OpenSSL v1.1.1 returns 253 as value while + # all other versions returned 256 as value + # Cannot find actual key size in bit for ED25519 private key + # but public key seems to be 256 bits + assert_equal 253, priv.keysize_in_bits + assert_equal 253, pub.keysize_in_bits + else + assert_equal 256, priv.keysize_in_bits + assert_equal 256, pub.keysize_in_bits + end rescue OpenSSL::PKey::PKeyError => e # OpenSSL < 1.1.1 From fb17bc9874af5d62f7b609acb83df7e378d26730 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 14 Nov 2023 23:29:10 +0800 Subject: [PATCH 6/8] Tested local seems ed25519 also returned 253 as bit size --- test/openssl/test_pkey.rb | 231 +++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 118 deletions(-) diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index 0bd41ceaa..d2aae3f92 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -1,84 +1,85 @@ # frozen_string_literal: true -require_relative "utils" + +require_relative 'utils' class OpenSSL::TestPKey < OpenSSL::PKeyTestCase def test_generic_oid_inspect # RSA private key - rsa = Fixtures.pkey("rsa-1") + rsa = Fixtures.pkey('rsa-1') assert_instance_of OpenSSL::PKey::RSA, rsa - assert_equal "rsaEncryption", rsa.oid - assert_match %r{oid=rsaEncryption}, rsa.inspect + assert_equal 'rsaEncryption', rsa.oid + assert_match(/oid=rsaEncryption/, rsa.inspect) # X25519 private key x25519_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq - -----END PRIVATE KEY----- + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq + -----END PRIVATE KEY----- EOF begin x25519 = OpenSSL::PKey.read(x25519_pem) rescue OpenSSL::PKey::PKeyError # OpenSSL < 1.1.0 - pend "X25519 is not implemented" + pend 'X25519 is not implemented' end assert_instance_of OpenSSL::PKey::PKey, x25519 - assert_equal "X25519", x25519.oid - assert_match %r{oid=X25519}, x25519.inspect + assert_equal 'X25519', x25519.oid + assert_match(/oid=X25519/, x25519.inspect) end def test_s_generate_parameters - pkey = OpenSSL::PKey.generate_parameters("EC", { - "ec_paramgen_curve" => "secp384r1", - }) + pkey = OpenSSL::PKey.generate_parameters('EC', { + 'ec_paramgen_curve' => 'secp384r1' + }) assert_instance_of OpenSSL::PKey::EC, pkey - assert_equal "secp384r1", pkey.group.curve_name + assert_equal 'secp384r1', pkey.group.curve_name assert_equal nil, pkey.private_key # Invalid options are checked - assert_raise(OpenSSL::PKey::PKeyError) { - OpenSSL::PKey.generate_parameters("EC", "invalid" => "option") - } + assert_raise(OpenSSL::PKey::PKeyError) do + OpenSSL::PKey.generate_parameters('EC', 'invalid' => 'option') + end # Parameter generation callback is called if openssl?(3, 0, 0, 0) && !openssl?(3, 0, 0, 6) # Errors in BN_GENCB were not properly handled. This special pend is to # suppress failures on Ubuntu 22.04, which uses OpenSSL 3.0.2. - pend "unstable test on OpenSSL 3.0.[0-5]" + pend 'unstable test on OpenSSL 3.0.[0-5]' end cb_called = [] - assert_raise(RuntimeError) { - OpenSSL::PKey.generate_parameters("DSA") { |*args| + assert_raise(RuntimeError) do + OpenSSL::PKey.generate_parameters('DSA') do |*args| cb_called << args - raise "exit!" if cb_called.size == 3 - } - } + raise 'exit!' if cb_called.size == 3 + end + end assert_not_empty cb_called end def test_s_generate_key - assert_raise(OpenSSL::PKey::PKeyError) { + assert_raise(OpenSSL::PKey::PKeyError) do # DSA key pair cannot be generated without parameters - OpenSSL::PKey.generate_key("DSA") - } - pkey_params = OpenSSL::PKey.generate_parameters("EC", { - "ec_paramgen_curve" => "secp384r1", - }) + OpenSSL::PKey.generate_key('DSA') + end + pkey_params = OpenSSL::PKey.generate_parameters('EC', { + 'ec_paramgen_curve' => 'secp384r1' + }) pkey = OpenSSL::PKey.generate_key(pkey_params) assert_instance_of OpenSSL::PKey::EC, pkey - assert_equal "secp384r1", pkey.group.curve_name + assert_equal 'secp384r1', pkey.group.curve_name assert_not_equal nil, pkey.private_key end def test_hmac_sign_verify - pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" }) + pkey = OpenSSL::PKey.generate_key('HMAC', { 'key' => 'abcd' }) - hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest - assert_equal hmac, pkey.sign("SHA256", "data") + hmac = OpenSSL::HMAC.new('abcd', 'SHA256').update('data').digest + assert_equal hmac, pkey.sign('SHA256', 'data') # EVP_PKEY_HMAC does not support verify - assert_raise(OpenSSL::PKey::PKeyError) { - pkey.verify("SHA256", "data", hmac) - } + assert_raise(OpenSSL::PKey::PKeyError) do + pkey.verify('SHA256', 'data', hmac) + end end def test_ed25519 @@ -87,21 +88,21 @@ def test_ed25519 # Test vector from RFC 8032 Section 7.1 TEST 2 priv_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 - -----END PRIVATE KEY----- + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 + -----END PRIVATE KEY----- EOF pub_pem = <<~EOF - -----BEGIN PUBLIC KEY----- - MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= - -----END PUBLIC KEY----- + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= + -----END PUBLIC KEY----- EOF begin priv = OpenSSL::PKey.read(priv_pem) pub = OpenSSL::PKey.read(pub_pem) rescue OpenSSL::PKey::PKeyError => e # OpenSSL < 1.1.1 - pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) + pend 'Ed25519 is not implemented' unless openssl?(1, 1, 1) raise e end @@ -112,33 +113,33 @@ def test_ed25519 assert_equal pub_pem, pub.public_to_pem begin - assert_equal "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", - priv.raw_private_key.unpack1("H*") - assert_equal OpenSSL::PKey.new_raw_private_key("ED25519", priv.raw_private_key).private_to_pem, - priv.private_to_pem - assert_equal "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", - priv.raw_public_key.unpack1("H*") - assert_equal OpenSSL::PKey.new_raw_public_key("ED25519", priv.raw_public_key).public_to_pem, - pub.public_to_pem + assert_equal '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb', + priv.raw_private_key.unpack1('H*') + assert_equal OpenSSL::PKey.new_raw_private_key('ED25519', priv.raw_private_key).private_to_pem, + priv.private_to_pem + assert_equal '3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c', + priv.raw_public_key.unpack1('H*') + assert_equal OpenSSL::PKey.new_raw_public_key('ED25519', priv.raw_public_key).public_to_pem, + pub.public_to_pem rescue NoMethodError - pend "running OpenSSL version does not have raw public key support" + pend 'running OpenSSL version does not have raw public key support' end - sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*") - 92a009a9f0d4cab8720e820b5f642540 - a2b27b5416503f8fb3762223ebdb69da - 085ac1e43e15996e458f3613d0f11d8c - 387b2eaeb4302aeeb00d291612bb0c00 + sig = [<<~EOF.gsub(/[^0-9a-f]/, '')].pack('H*') + 92a009a9f0d4cab8720e820b5f642540 + a2b27b5416503f8fb3762223ebdb69da + 085ac1e43e15996e458f3613d0f11d8c + 387b2eaeb4302aeeb00d291612bb0c00 EOF - data = ["72"].pack("H*") + data = ['72'].pack('H*') assert_equal sig, priv.sign(nil, data) assert_equal true, priv.verify(nil, sig, data) assert_equal true, pub.verify(nil, sig, data) assert_equal false, pub.verify(nil, sig, data.succ) # PureEdDSA wants nil as the message digest - assert_raise(OpenSSL::PKey::PKeyError) { priv.sign("SHA512", data) } - assert_raise(OpenSSL::PKey::PKeyError) { pub.verify("SHA512", sig, data) } + assert_raise(OpenSSL::PKey::PKeyError) { priv.sign('SHA512', data) } + assert_raise(OpenSSL::PKey::PKeyError) { pub.verify('SHA512', sig, data) } # Ed25519 pkey type does not support key derivation assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } @@ -156,14 +157,12 @@ def test_ed25519_not_approved_on_fips # See also # https://github.com/openssl/openssl/issues/20758#issuecomment-1639658102 # for details. - unless openssl?(3, 1, 0, 0) - omit 'Ed25519 is allowed in the OpenSSL 3.0 FIPS code as a kind of bug' - end + omit 'Ed25519 is allowed in the OpenSSL 3.0 FIPS code as a kind of bug' unless openssl?(3, 1, 0, 0) priv_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 - -----END PRIVATE KEY----- + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 + -----END PRIVATE KEY----- EOF assert_raise(OpenSSL::PKey::PKeyError) do OpenSSL::PKey.read(priv_pem) @@ -173,60 +172,60 @@ def test_ed25519_not_approved_on_fips def test_x25519 # Test vector from RFC 7748 Section 6.1 alice_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq - -----END PRIVATE KEY----- + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq + -----END PRIVATE KEY----- EOF bob_pem = <<~EOF - -----BEGIN PUBLIC KEY----- - MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= - -----END PUBLIC KEY----- + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= + -----END PUBLIC KEY----- EOF - shared_secret = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" + shared_secret = '4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742' begin alice = OpenSSL::PKey.read(alice_pem) bob = OpenSSL::PKey.read(bob_pem) rescue OpenSSL::PKey::PKeyError # OpenSSL < 1.1.0 - pend "X25519 is not implemented" + pend 'X25519 is not implemented' end assert_instance_of OpenSSL::PKey::PKey, alice assert_equal alice_pem, alice.private_to_pem assert_equal bob_pem, bob.public_to_pem - assert_equal [shared_secret].pack("H*"), alice.derive(bob) + assert_equal [shared_secret].pack('H*'), alice.derive(bob) begin - alice_private = OpenSSL::PKey.new_raw_private_key("X25519", alice.raw_private_key) - bob_public = OpenSSL::PKey.new_raw_public_key("X25519", bob.raw_public_key) - alice_private_raw = alice.raw_private_key.unpack1("H*") - bob_public_raw = bob.raw_public_key.unpack1("H*") + alice_private = OpenSSL::PKey.new_raw_private_key('X25519', alice.raw_private_key) + bob_public = OpenSSL::PKey.new_raw_public_key('X25519', bob.raw_public_key) + alice_private_raw = alice.raw_private_key.unpack1('H*') + bob_public_raw = bob.raw_public_key.unpack1('H*') rescue NoMethodError # OpenSSL < 1.1.1 - pend "running OpenSSL version does not have raw public key support" + pend 'running OpenSSL version does not have raw public key support' end assert_equal alice_private.private_to_pem, - alice.private_to_pem + alice.private_to_pem assert_equal bob_public.public_to_pem, - bob.public_to_pem - assert_equal "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", - alice_private_raw - assert_equal "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", - bob_public_raw + bob.public_to_pem + assert_equal '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a', + alice_private_raw + assert_equal 'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f', + bob_public_raw end def raw_initialize - pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) # >= v1.1.1 + pend 'Ed25519 is not implemented' unless openssl?(1, 1, 1) # >= v1.1.1 - assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("foo123", "xxx") } - assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("ED25519", "xxx") } - assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("foo123", "xxx") } - assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("ED25519", "xxx") } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key('foo123', 'xxx') } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key('ED25519', 'xxx') } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key('foo123', 'xxx') } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key('ED25519', 'xxx') } end def test_compare? - key1 = Fixtures.pkey("rsa1024") - key2 = Fixtures.pkey("rsa1024") - key3 = Fixtures.pkey("rsa2048") - key4 = Fixtures.pkey("dh-1") + key1 = Fixtures.pkey('rsa1024') + key2 = Fixtures.pkey('rsa1024') + key3 = Fixtures.pkey('rsa2048') + key4 = Fixtures.pkey('dh-1') assert_equal(true, key1.compare?(key2)) assert_equal(true, key1.public_key.compare?(key2)) @@ -241,51 +240,50 @@ def test_compare? end def test_to_text - rsa = Fixtures.pkey("rsa1024") - assert_include rsa.to_text, "publicExponent" + rsa = Fixtures.pkey('rsa1024') + assert_include rsa.to_text, 'publicExponent' end def test_keysize_in_bits # Test vector from RFC 7748 Section 6.1 alice_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq - -----END PRIVATE KEY----- + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq + -----END PRIVATE KEY----- EOF bob_pem = <<~EOF - -----BEGIN PUBLIC KEY----- - MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= - -----END PUBLIC KEY----- + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= + -----END PUBLIC KEY----- EOF begin alice = OpenSSL::PKey.read(alice_pem) bob = OpenSSL::PKey.read(bob_pem) - + assert_equal 253, alice.keysize_in_bits assert_equal 253, bob.keysize_in_bits - rescue OpenSSL::PKey::PKeyError # OpenSSL < 1.1.0 - pend "X25519 is not implemented" + pend 'X25519 is not implemented' end # Test vector from RFC 8032 Section 7.1 TEST 2 priv_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 - -----END PRIVATE KEY----- + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 + -----END PRIVATE KEY----- EOF pub_pem = <<~EOF - -----BEGIN PUBLIC KEY----- - MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= - -----END PUBLIC KEY----- + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= + -----END PUBLIC KEY----- EOF begin priv = OpenSSL::PKey.read(priv_pem) pub = OpenSSL::PKey.read(pub_pem) - if openssl?(1,1,1) - # for some reason OpenSSL v1.1.1 returns 253 as value while + if openssl?(1, 1, 1) or openssl?(3, 0, 0) + # for some reason OpenSSL v1.1.1 returns 253 as value while # all other versions returned 256 as value # Cannot find actual key size in bit for ED25519 private key # but public key seems to be 256 bits @@ -295,12 +293,9 @@ def test_keysize_in_bits assert_equal 256, priv.keysize_in_bits assert_equal 256, pub.keysize_in_bits end - rescue OpenSSL::PKey::PKeyError => e # OpenSSL < 1.1.1 - pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) + pend 'Ed25519 is not implemented' unless openssl?(1, 1, 1) end - end - end From db2ac8a892da062ff7ae286abba21bf380bbf138 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 15 Nov 2023 15:35:43 +0800 Subject: [PATCH 7/8] Not getting consistance result on ED25519 keysize --- test/openssl/test_pkey.rb | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index d2aae3f92..34dcca68c 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -266,36 +266,5 @@ def test_keysize_in_bits # OpenSSL < 1.1.0 pend 'X25519 is not implemented' end - - # Test vector from RFC 8032 Section 7.1 TEST 2 - priv_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 - -----END PRIVATE KEY----- - EOF - pub_pem = <<~EOF - -----BEGIN PUBLIC KEY----- - MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= - -----END PUBLIC KEY----- - EOF - begin - priv = OpenSSL::PKey.read(priv_pem) - pub = OpenSSL::PKey.read(pub_pem) - - if openssl?(1, 1, 1) or openssl?(3, 0, 0) - # for some reason OpenSSL v1.1.1 returns 253 as value while - # all other versions returned 256 as value - # Cannot find actual key size in bit for ED25519 private key - # but public key seems to be 256 bits - assert_equal 253, priv.keysize_in_bits - assert_equal 253, pub.keysize_in_bits - else - assert_equal 256, priv.keysize_in_bits - assert_equal 256, pub.keysize_in_bits - end - rescue OpenSSL::PKey::PKeyError => e - # OpenSSL < 1.1.1 - pend 'Ed25519 is not implemented' unless openssl?(1, 1, 1) - end end end From 5ce7e11d2fa11f3a65683b58cbc432afa46f584b Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Nov 2023 11:08:14 +0800 Subject: [PATCH 8/8] Change name to bits instead of keysize_in_bits and remove some additional spaces --- ext/openssl/ossl_pkey.c | 19 +++++++------------ test/openssl/test_pkey.rb | 21 +++------------------ test/openssl/test_pkey_ec.rb | 30 +++++++----------------------- 3 files changed, 17 insertions(+), 53 deletions(-) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 7f622b227..9683dafb3 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -749,18 +749,17 @@ ossl_pkey_inspect(VALUE self) static VALUE ossl_pkey_length_in_bits(VALUE self) { - EVP_PKEY * pkey; - int bits; + EVP_PKEY * pkey; + int bits; - GetPKey(self, pkey); + GetPKey(self, pkey); #if OSSL_OPENSSL_PREREQ(3, 0, 0) - bits = EVP_PKEY_get_bits(pkey); + bits = EVP_PKEY_get_bits(pkey); #else - bits = EVP_PKEY_bits(pkey); + bits = EVP_PKEY_bits(pkey); #endif - return INT2NUM(bits); - + return INT2NUM(bits); } /* @@ -1692,8 +1691,6 @@ ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) return str; } - - /* * INIT */ @@ -1793,7 +1790,7 @@ Init_ossl_pkey(void) #endif rb_define_method(cPKey, "oid", ossl_pkey_oid, 0); rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0); - rb_define_method(cPKey, "keysize_in_bits", ossl_pkey_length_in_bits, 0); + rb_define_method(cPKey, "bits", ossl_pkey_length_in_bits, 0); rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0); rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1); rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1); @@ -1814,8 +1811,6 @@ Init_ossl_pkey(void) rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1); rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1); - - id_private_q = rb_intern("private?"); /* diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index 34dcca68c..4977a79ee 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true - require_relative 'utils' class OpenSSL::TestPKey < OpenSSL::PKeyTestCase @@ -244,24 +243,10 @@ def test_to_text assert_include rsa.to_text, 'publicExponent' end - def test_keysize_in_bits - # Test vector from RFC 7748 Section 6.1 - alice_pem = <<~EOF - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq - -----END PRIVATE KEY----- - EOF - bob_pem = <<~EOF - -----BEGIN PUBLIC KEY----- - MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08= - -----END PUBLIC KEY----- - EOF + def test_keysize_bits begin - alice = OpenSSL::PKey.read(alice_pem) - bob = OpenSSL::PKey.read(bob_pem) - - assert_equal 253, alice.keysize_in_bits - assert_equal 253, bob.keysize_in_bits + x25519 = OpenSSL::PKey.generate_key("X25519") + assert_equal 253, x25519.bits rescue OpenSSL::PKey::PKeyError # OpenSSL < 1.1.0 pend 'X25519 is not implemented' diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index b2f2304a9..9d44c9af3 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -71,30 +71,14 @@ def test_marshal assert_equal key.to_der, deserialized.to_der end - def test_keysize_in_bits - OpenSSL::PKey::EC.builtin_curves.map { |name, comment| name }.each do |curve| - if !openssl?(3, 0, 0) - ec = OpenSSL::PKey::EC.new(curve) - ec.generate_key! - else - ec = OpenSSL::PKey::EC.generate(curve) - end - - case curve - when "secp224r1" - assert_equal(224, ec.keysize_in_bits) - when "secp256r1", "brainpoolP256r1", "brainpoolP256t1", "prime256v1" - assert_equal(256, ec.keysize_in_bits) - when "secp384r1", "brainpoolP384r1", "brainpoolP384t1" - assert_equal(384, ec.keysize_in_bits) - when "secp521r1" - assert_equal(521, ec.keysize_in_bits) - when "brainpoolP512r1", "brainpoolP512t1" - assert_equal(512, ec.keysize_in_bits) - when "brainpoolP320r1", "brainpoolP320t1" - assert_equal(320, ec.keysize_in_bits) - end + def test_keysize_bits + if !openssl?(3, 0, 0) + ec = OpenSSL::PKey::EC.new("prime256v1") + ec.generate_key! + else + ec = OpenSSL::PKey::EC.generate("prime256v1") end + assert_equal(256, ec.bits) end def test_check_key