Skip to content

Commit ad35a4b

Browse files
rheniummatzbot
authored andcommitted
[ruby/openssl] pkey: disallow {DH,DSA,EC,RSA}.new without arguments with OpenSSL 3.0
Raise ArgumentError if this is attempted when the extension is compiled with OpenSSL 3.0 or later. The form will be fully removed when we drop support for OpenSSL 1.1.1. When OpenSSL::PKey::{DH,DSA,EC,RSA}.new is called without any arguments, it sets up an empty corresponding low-level struct and wraps it in an EVP_PKEY. This is useful when the user later fills the missing fields using low-level setter methods such as OpenSSL::PKey::RSA#set_key. Such setter methods are not compatible with OpenSSL 3.0 or later, where EVP_PKEY is immutable once created. This means that the ability to create an empty instance is useless. ruby/openssl@affd569f78
1 parent 986d917 commit ad35a4b

File tree

8 files changed

+71
-20
lines changed

8 files changed

+71
-20
lines changed

ext/openssl/ossl_pkey_dh.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static VALUE eDHError;
4343
* If called without arguments, an empty instance without any parameter or key
4444
* components is created. Use #set_pqg to manually set the parameters afterwards
4545
* (and optionally #set_key to set private and public key components).
46+
* This form is not compatible with OpenSSL 3.0 or later.
4647
*
4748
* If a String is given, tries to parse it as a DER- or PEM- encoded parameters.
4849
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -58,14 +59,15 @@ static VALUE eDHError;
5859
*
5960
* Examples:
6061
* # Creating an instance from scratch
61-
* # Note that this is deprecated and will not work on OpenSSL 3.0 or later.
62+
* # Note that this is deprecated and will result in ArgumentError when
63+
* # using OpenSSL 3.0 or later.
6264
* dh = OpenSSL::PKey::DH.new
6365
* dh.set_pqg(bn_p, nil, bn_g)
6466
*
6567
* # Generating a parameters and a key pair
6668
* dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048)
6769
*
68-
* # Reading DH parameters
70+
* # Reading DH parameters from a PEM-encoded string
6971
* dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only
7072
* dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair
7173
*/
@@ -84,10 +86,15 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
8486

8587
/* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
8688
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
89+
#ifdef OSSL_HAVE_IMMUTABLE_PKEY
90+
rb_raise(rb_eArgError, "OpenSSL::PKey::DH.new cannot be called " \
91+
"without arguments; pkeys are immutable with OpenSSL 3.0");
92+
#else
8793
dh = DH_new();
8894
if (!dh)
8995
ossl_raise(eDHError, "DH_new");
9096
goto legacy;
97+
#endif
9198
}
9299

93100
arg = ossl_to_der_if_possible(arg);

ext/openssl/ossl_pkey_dsa.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ static VALUE eDSAError;
5656
*
5757
* If called without arguments, creates a new instance with no key components
5858
* set. They can be set individually by #set_pqg and #set_key.
59+
* This form is not compatible with OpenSSL 3.0 or later.
5960
*
6061
* If called with a String, tries to parse as DER or PEM encoding of a \DSA key.
6162
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -96,10 +97,15 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
9697
/* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
9798
rb_scan_args(argc, argv, "02", &arg, &pass);
9899
if (argc == 0) {
100+
#ifdef OSSL_HAVE_IMMUTABLE_PKEY
101+
rb_raise(rb_eArgError, "OpenSSL::PKey::DSA.new cannot be called " \
102+
"without arguments; pkeys are immutable with OpenSSL 3.0");
103+
#else
99104
dsa = DSA_new();
100105
if (!dsa)
101106
ossl_raise(eDSAError, "DSA_new");
102107
goto legacy;
108+
#endif
103109
}
104110

105111
pass = ossl_pem_passwd_value(pass);

ext/openssl/ossl_pkey_ec.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,14 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
147147

148148
rb_scan_args(argc, argv, "02", &arg, &pass);
149149
if (NIL_P(arg)) {
150+
#ifdef OSSL_HAVE_IMMUTABLE_PKEY
151+
rb_raise(rb_eArgError, "OpenSSL::PKey::EC.new cannot be called " \
152+
"without arguments; pkeys are immutable with OpenSSL 3.0");
153+
#else
150154
if (!(ec = EC_KEY_new()))
151155
ossl_raise(eECError, "EC_KEY_new");
152156
goto legacy;
157+
#endif
153158
}
154159
else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
155160
ec = ec_key_new_from_group(arg);

ext/openssl/ossl_pkey_rsa.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ static VALUE eRSAError;
5959
* If called without arguments, creates a new instance with no key components
6060
* set. They can be set individually by #set_key, #set_factors, and
6161
* #set_crt_params.
62+
* This form is not compatible with OpenSSL 3.0 or later.
6263
*
6364
* If called with a String, tries to parse as DER or PEM encoding of an \RSA key.
6465
* Note that if _password_ is not specified, but the key is encrypted with a
@@ -89,10 +90,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
8990
/* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
9091
rb_scan_args(argc, argv, "02", &arg, &pass);
9192
if (argc == 0) {
93+
#ifdef OSSL_HAVE_IMMUTABLE_PKEY
94+
rb_raise(rb_eArgError, "OpenSSL::PKey::RSA.new cannot be called " \
95+
"without arguments; pkeys are immutable with OpenSSL 3.0");
96+
#else
9297
rsa = RSA_new();
9398
if (!rsa)
9499
ossl_raise(eRSAError, "RSA_new");
95100
goto legacy;
101+
#endif
96102
}
97103

98104
pass = ossl_pem_passwd_value(pass);

test/openssl/test_pkey_dh.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
77
NEW_KEYLEN = 2048
88

99
def test_new_empty
10-
dh = OpenSSL::PKey::DH.new
11-
assert_equal nil, dh.p
12-
assert_equal nil, dh.priv_key
10+
# pkeys are immutable with OpenSSL >= 3.0
11+
if openssl?(3, 0, 0)
12+
assert_raise(ArgumentError) { OpenSSL::PKey::DH.new }
13+
else
14+
dh = OpenSSL::PKey::DH.new
15+
assert_nil(dh.p)
16+
assert_nil(dh.priv_key)
17+
end
1318
end
1419

1520
def test_new_generate

test/openssl/test_pkey_dsa.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,14 @@ def test_new_break
3434
end
3535

3636
def test_new_empty
37-
key = OpenSSL::PKey::DSA.new
38-
assert_nil(key.p)
39-
assert_raise(OpenSSL::PKey::PKeyError) { key.to_der }
37+
# pkeys are immutable with OpenSSL >= 3.0
38+
if openssl?(3, 0, 0)
39+
assert_raise(ArgumentError) { OpenSSL::PKey::DSA.new }
40+
else
41+
key = OpenSSL::PKey::DSA.new
42+
assert_nil(key.p)
43+
assert_raise(OpenSSL::PKey::PKeyError) { key.to_der }
44+
end
4045
end
4146

4247
def test_generate

test/openssl/test_pkey_ec.rb

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,9 @@
44
if defined?(OpenSSL)
55

66
class OpenSSL::TestEC < OpenSSL::PKeyTestCase
7-
def test_ec_key
7+
def test_ec_key_new
88
key1 = OpenSSL::PKey::EC.generate("prime256v1")
99

10-
# PKey is immutable in OpenSSL >= 3.0; constructing an empty EC object is
11-
# deprecated
12-
if !openssl?(3, 0, 0)
13-
key2 = OpenSSL::PKey::EC.new
14-
key2.group = key1.group
15-
key2.private_key = key1.private_key
16-
key2.public_key = key1.public_key
17-
assert_equal key1.to_der, key2.to_der
18-
end
19-
2010
key3 = OpenSSL::PKey::EC.new(key1)
2111
assert_equal key1.to_der, key3.to_der
2212

@@ -35,6 +25,23 @@ def test_ec_key
3525
end
3626
end
3727

28+
def test_ec_key_new_empty
29+
# pkeys are immutable with OpenSSL >= 3.0; constructing an empty EC object is
30+
# disallowed
31+
if openssl?(3, 0, 0)
32+
assert_raise(ArgumentError) { OpenSSL::PKey::EC.new }
33+
else
34+
key = OpenSSL::PKey::EC.new
35+
assert_nil(key.group)
36+
37+
p256 = Fixtures.pkey("p256")
38+
key.group = p256.group
39+
key.private_key = p256.private_key
40+
key.public_key = p256.public_key
41+
assert_equal(p256.to_der, key.to_der)
42+
end
43+
end
44+
3845
def test_builtin_curves
3946
builtin_curves = OpenSSL::PKey::EC.builtin_curves
4047
assert_not_empty builtin_curves

test/openssl/test_pkey_rsa.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ def test_new_public_exponent
6161
assert_equal 3, key.e
6262
end
6363

64+
def test_new_empty
65+
# pkeys are immutable with OpenSSL >= 3.0
66+
if openssl?(3, 0, 0)
67+
assert_raise(ArgumentError) { OpenSSL::PKey::RSA.new }
68+
else
69+
key = OpenSSL::PKey::RSA.new
70+
assert_nil(key.n)
71+
end
72+
end
73+
6474
def test_s_generate
6575
key1 = OpenSSL::PKey::RSA.generate(2048)
6676
assert_equal 2048, key1.n.num_bits
@@ -181,7 +191,7 @@ def test_verify_empty_rsa
181191
assert_raise(OpenSSL::PKey::PKeyError, "[Bug #12783]") {
182192
rsa.verify("SHA1", "a", "b")
183193
}
184-
end
194+
end unless openssl?(3, 0, 0) # Empty RSA is not possible with OpenSSL >= 3.0
185195

186196
def test_sign_verify_pss
187197
key = Fixtures.pkey("rsa2048")

0 commit comments

Comments
 (0)