Skip to content

Commit 6848d2d

Browse files
committed
pkey: deprecate PKey#set_* methods
OpenSSL 3.0 made EVP_PKEY immutable. This means we can only have a const pointer of the low level struct and the following methods can no longer be provided when linked against OpenSSL 3.0: - OpenSSL::PKey::RSA#set_key - OpenSSL::PKey::RSA#set_factors - OpenSSL::PKey::RSA#set_crt_params - OpenSSL::PKey::DSA#set_pqg - OpenSSL::PKey::DSA#set_key - OpenSSL::PKey::DH#set_pqg - OpenSSL::PKey::DH#set_key - OpenSSL::PKey::EC#group= - OpenSSL::PKey::EC#private_key= - OpenSSL::PKey::EC#public_key= There is no direct replacement for this functionality at the moment. I plan to introduce a wrapper around EVP_PKEY_fromdata(), which takes all key components at once to construct an EVP_PKEY.
1 parent 5e2e66c commit 6848d2d

File tree

6 files changed

+149
-68
lines changed

6 files changed

+149
-68
lines changed

ext/openssl/ossl_pkey.h

+16
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
124124
OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
125125
_type##_get0_##_group(obj, NULL, &bn))
126126

127+
#if !OSSL_OPENSSL_PREREQ(3, 0, 0)
127128
#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
128129
/* \
129130
* call-seq: \
@@ -181,6 +182,21 @@ static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
181182
} \
182183
return self; \
183184
}
185+
#else
186+
#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
187+
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
188+
{ \
189+
rb_raise(ePKeyError, \
190+
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
191+
}
192+
193+
#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
194+
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
195+
{ \
196+
rb_raise(ePKeyError, \
197+
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
198+
}
199+
#endif
184200

185201
#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \
186202
OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \

ext/openssl/ossl_pkey_ec.c

+12
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ ossl_ec_key_get_group(VALUE self)
237237
static VALUE
238238
ossl_ec_key_set_group(VALUE self, VALUE group_v)
239239
{
240+
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
241+
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
242+
#else
240243
EC_KEY *ec;
241244
EC_GROUP *group;
242245

@@ -247,6 +250,7 @@ ossl_ec_key_set_group(VALUE self, VALUE group_v)
247250
ossl_raise(eECError, "EC_KEY_set_group");
248251

249252
return group_v;
253+
#endif
250254
}
251255

252256
/*
@@ -275,6 +279,9 @@ static VALUE ossl_ec_key_get_private_key(VALUE self)
275279
*/
276280
static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
277281
{
282+
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
283+
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
284+
#else
278285
EC_KEY *ec;
279286
BIGNUM *bn = NULL;
280287

@@ -294,6 +301,7 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
294301
}
295302

296303
return private_key;
304+
#endif
297305
}
298306

299307
/*
@@ -322,6 +330,9 @@ static VALUE ossl_ec_key_get_public_key(VALUE self)
322330
*/
323331
static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
324332
{
333+
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
334+
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
335+
#else
325336
EC_KEY *ec;
326337
EC_POINT *point = NULL;
327338

@@ -341,6 +352,7 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
341352
}
342353

343354
return public_key;
355+
#endif
344356
}
345357

346358
/*

test/openssl/test_pkey_dh.rb

+26-12
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,32 @@ def test_params_ok?
107107
end
108108

109109
def test_dup
110-
dh = Fixtures.pkey("dh1024")
111-
dh2 = dh.dup
112-
assert_equal dh.to_der, dh2.to_der # params
113-
assert_equal_params dh, dh2 # keys
114-
dh2.set_pqg(dh2.p + 1, nil, dh2.g)
115-
assert_not_equal dh2.p, dh.p
116-
assert_equal dh2.g, dh.g
110+
# Parameters only
111+
dh1 = Fixtures.pkey("dh1024")
112+
dh2 = dh1.dup
113+
assert_equal dh1.to_der, dh2.to_der
114+
assert_not_equal nil, dh1.p
115+
assert_not_equal nil, dh1.g
116+
assert_equal [dh1.p, dh1.g], [dh2.p, dh2.g]
117+
assert_equal nil, dh1.pub_key
118+
assert_equal nil, dh1.priv_key
119+
assert_equal [dh1.pub_key, dh1.priv_key], [dh2.pub_key, dh2.priv_key]
120+
121+
# PKey is immutable in OpenSSL >= 3.0
122+
if !openssl?(3, 0, 0)
123+
dh2.set_pqg(dh2.p + 1, nil, dh2.g)
124+
assert_not_equal dh2.p, dh1.p
125+
end
126+
127+
# With a key pair
128+
dh3 = OpenSSL::PKey.generate_key(Fixtures.pkey("dh1024"))
129+
dh4 = dh3.dup
130+
assert_equal dh3.to_der, dh4.to_der
131+
assert_equal dh1.to_der, dh4.to_der # encodes parameters only
132+
assert_equal [dh1.p, dh1.g], [dh4.p, dh4.g]
133+
assert_not_equal nil, dh3.pub_key
134+
assert_not_equal nil, dh3.priv_key
135+
assert_equal [dh3.pub_key, dh3.priv_key], [dh4.pub_key, dh4.priv_key]
117136
end
118137

119138
def test_marshal
@@ -125,11 +144,6 @@ def test_marshal
125144

126145
private
127146

128-
def assert_equal_params(dh1, dh2)
129-
assert_equal(dh1.g, dh2.g)
130-
assert_equal(dh1.p, dh2.p)
131-
end
132-
133147
def assert_no_key(dh)
134148
assert_equal(false, dh.public?)
135149
assert_equal(false, dh.private?)

test/openssl/test_pkey_dsa.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,12 @@ def test_dup
208208
key = Fixtures.pkey("dsa1024")
209209
key2 = key.dup
210210
assert_equal key.params, key2.params
211-
key2.set_pqg(key2.p + 1, key2.q, key2.g)
212-
assert_not_equal key.params, key2.params
211+
212+
# PKey is immutable in OpenSSL >= 3.0
213+
if !openssl?(3, 0, 0)
214+
key2.set_pqg(key2.p + 1, key2.q, key2.g)
215+
assert_not_equal key.params, key2.params
216+
end
213217
end
214218

215219
def test_marshal

test/openssl/test_pkey_ec.rb

+35-23
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@ def test_ec_key
2121

2222
key1 = OpenSSL::PKey::EC.generate("prime256v1")
2323

24-
key2 = OpenSSL::PKey::EC.new
25-
key2.group = key1.group
26-
key2.private_key = key1.private_key
27-
key2.public_key = key1.public_key
28-
assert_equal key1.to_der, key2.to_der
24+
# PKey is immutable in OpenSSL >= 3.0; constructing an empty EC object is
25+
# deprecated
26+
if !openssl?(3, 0, 0)
27+
key2 = OpenSSL::PKey::EC.new
28+
key2.group = key1.group
29+
key2.private_key = key1.private_key
30+
key2.public_key = key1.public_key
31+
assert_equal key1.to_der, key2.to_der
32+
end
2933

3034
key3 = OpenSSL::PKey::EC.new(key1)
3135
assert_equal key1.to_der, key3.to_der
@@ -35,10 +39,14 @@ def test_ec_key
3539

3640
key5 = key1.dup
3741
assert_equal key1.to_der, key5.to_der
38-
key_tmp = OpenSSL::PKey::EC.new("prime256v1").generate_key!
39-
key5.private_key = key_tmp.private_key
40-
key5.public_key = key_tmp.public_key
41-
assert_not_equal key1.to_der, key5.to_der
42+
43+
# PKey is immutable in OpenSSL >= 3.0; EC object should not be modified
44+
if !openssl?(3, 0, 0)
45+
key_tmp = OpenSSL::PKey::EC.generate("prime256v1")
46+
key5.private_key = key_tmp.private_key
47+
key5.public_key = key_tmp.public_key
48+
assert_not_equal key1.to_der, key5.to_der
49+
end
4250
end
4351

4452
def test_generate
@@ -65,22 +73,26 @@ def test_marshal
6573
end
6674

6775
def test_check_key
68-
key = OpenSSL::PKey::EC.new("prime256v1").generate_key!
69-
assert_equal(true, key.check_key)
70-
assert_equal(true, key.private?)
71-
assert_equal(true, key.public?)
72-
key2 = OpenSSL::PKey::EC.new(key.group)
73-
assert_equal(false, key2.private?)
74-
assert_equal(false, key2.public?)
75-
key2.public_key = key.public_key
76-
assert_equal(false, key2.private?)
77-
assert_equal(true, key2.public?)
78-
key2.private_key = key.private_key
76+
key0 = Fixtures.pkey("p256")
77+
assert_equal(true, key0.check_key)
78+
assert_equal(true, key0.private?)
79+
assert_equal(true, key0.public?)
80+
81+
key1 = OpenSSL::PKey.read(key0.public_to_der)
82+
assert_equal(true, key1.check_key)
83+
assert_equal(false, key1.private?)
84+
assert_equal(true, key1.public?)
85+
86+
key2 = OpenSSL::PKey.read(key0.private_to_der)
7987
assert_equal(true, key2.private?)
8088
assert_equal(true, key2.public?)
8189
assert_equal(true, key2.check_key)
82-
key2.private_key += 1
83-
assert_raise(OpenSSL::PKey::ECError) { key2.check_key }
90+
91+
# EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0
92+
if !openssl?(3, 0, 0)
93+
key2.private_key += 1
94+
assert_raise(OpenSSL::PKey::ECError) { key2.check_key }
95+
end
8496
end
8597

8698
def test_sign_verify
@@ -112,7 +124,7 @@ def test_derive_key
112124
assert_equal [zIUT].pack("H*"), a.derive(b)
113125

114126
assert_equal a.derive(b), a.dh_compute_key(b.public_key)
115-
end
127+
end if !openssl?(3, 0, 0) # TODO: Test it without using #private_key=
116128

117129
def test_sign_verify_raw
118130
key = Fixtures.pkey("p256")

test/openssl/test_pkey_rsa.rb

+54-31
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,18 @@ def test_private
3131
assert(!key4.private?)
3232
rsa1024 = Fixtures.pkey("rsa1024")
3333

34-
# Generated by RSA#set_key
35-
key5 = OpenSSL::PKey::RSA.new
36-
key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
37-
assert(key5.private?)
38-
39-
# Generated by RSA#set_key, without d
40-
key6 = OpenSSL::PKey::RSA.new
41-
key6.set_key(rsa1024.n, rsa1024.e, nil)
42-
assert(!key6.private?)
34+
if !openssl?(3, 0, 0)
35+
key = OpenSSL::PKey::RSA.new
36+
# Generated by RSA#set_key
37+
key5 = OpenSSL::PKey::RSA.new
38+
key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
39+
assert(key5.private?)
40+
41+
# Generated by RSA#set_key, without d
42+
key6 = OpenSSL::PKey::RSA.new
43+
key6.set_key(rsa1024.n, rsa1024.e, nil)
44+
assert(!key6.private?)
45+
end
4346
end
4447

4548
def test_new
@@ -235,36 +238,52 @@ def test_encrypt_decrypt_legacy
235238

236239
def test_export
237240
rsa1024 = Fixtures.pkey("rsa1024")
238-
key = OpenSSL::PKey::RSA.new
239241

240-
# key has only n, e and d
241-
key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
242-
assert_equal rsa1024.public_key.export, key.export
242+
pub = OpenSSL::PKey.read(rsa1024.public_to_der)
243+
assert_not_equal rsa1024.export, pub.export
244+
assert_equal rsa1024.public_to_pem, pub.export
245+
246+
# PKey is immutable in OpenSSL >= 3.0
247+
if !openssl?(3, 0, 0)
248+
key = OpenSSL::PKey::RSA.new
243249

244-
# key has only n, e, d, p and q
245-
key.set_factors(rsa1024.p, rsa1024.q)
246-
assert_equal rsa1024.public_key.export, key.export
250+
# key has only n, e and d
251+
key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
252+
assert_equal rsa1024.public_key.export, key.export
247253

248-
# key has n, e, d, p, q, dmp1, dmq1 and iqmp
249-
key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
250-
assert_equal rsa1024.export, key.export
254+
# key has only n, e, d, p and q
255+
key.set_factors(rsa1024.p, rsa1024.q)
256+
assert_equal rsa1024.public_key.export, key.export
257+
258+
# key has n, e, d, p, q, dmp1, dmq1 and iqmp
259+
key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
260+
assert_equal rsa1024.export, key.export
261+
end
251262
end
252263

253264
def test_to_der
254265
rsa1024 = Fixtures.pkey("rsa1024")
255-
key = OpenSSL::PKey::RSA.new
256266

257-
# key has only n, e and d
258-
key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
259-
assert_equal rsa1024.public_key.to_der, key.to_der
267+
pub = OpenSSL::PKey.read(rsa1024.public_to_der)
268+
assert_not_equal rsa1024.to_der, pub.to_der
269+
assert_equal rsa1024.public_to_der, pub.to_der
260270

261-
# key has only n, e, d, p and q
262-
key.set_factors(rsa1024.p, rsa1024.q)
263-
assert_equal rsa1024.public_key.to_der, key.to_der
271+
# PKey is immutable in OpenSSL >= 3.0
272+
if !openssl?(3, 0, 0)
273+
key = OpenSSL::PKey::RSA.new
264274

265-
# key has n, e, d, p, q, dmp1, dmq1 and iqmp
266-
key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
267-
assert_equal rsa1024.to_der, key.to_der
275+
# key has only n, e and d
276+
key.set_key(rsa1024.n, rsa1024.e, rsa1024.d)
277+
assert_equal rsa1024.public_key.to_der, key.to_der
278+
279+
# key has only n, e, d, p and q
280+
key.set_factors(rsa1024.p, rsa1024.q)
281+
assert_equal rsa1024.public_key.to_der, key.to_der
282+
283+
# key has n, e, d, p, q, dmp1, dmq1 and iqmp
284+
key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp)
285+
assert_equal rsa1024.to_der, key.to_der
286+
end
268287
end
269288

270289
def test_RSAPrivateKey
@@ -495,8 +514,12 @@ def test_dup
495514
key = Fixtures.pkey("rsa1024")
496515
key2 = key.dup
497516
assert_equal key.params, key2.params
498-
key2.set_key(key2.n, 3, key2.d)
499-
assert_not_equal key.params, key2.params
517+
518+
# PKey is immutable in OpenSSL >= 3.0
519+
if !openssl?(3, 0, 0)
520+
key2.set_key(key2.n, 3, key2.d)
521+
assert_not_equal key.params, key2.params
522+
end
500523
end
501524

502525
def test_marshal

0 commit comments

Comments
 (0)