Skip to content

Commit 88b7577

Browse files
authored
Merge pull request #478 from rhenium/ky/pkey-base-dup
pkey: allocate EVP_PKEY on #initialize
2 parents 1cd0667 + 66cd8cb commit 88b7577

File tree

7 files changed

+262
-169
lines changed

7 files changed

+262
-169
lines changed

ext/openssl/extconf.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ def find_openssl_library
179179
have_func("EVP_MD_CTX_get0_md")
180180
have_func("EVP_MD_CTX_get_pkey_ctx")
181181
have_func("EVP_PKEY_eq")
182+
have_func("EVP_PKEY_dup")
182183

183184
Logging::message "=== Checking done. ===\n"
184185

ext/openssl/ossl_pkey.c

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,8 @@ pkey_new0(VALUE arg)
3939
{
4040
EVP_PKEY *pkey = (EVP_PKEY *)arg;
4141
VALUE klass, obj;
42-
int type;
4342

44-
if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
45-
ossl_raise(rb_eRuntimeError, "pkey is empty");
46-
47-
switch (type) {
43+
switch (EVP_PKEY_base_id(pkey)) {
4844
#if !defined(OPENSSL_NO_RSA)
4945
case EVP_PKEY_RSA: klass = cRSA; break;
5046
#endif
@@ -59,8 +55,8 @@ pkey_new0(VALUE arg)
5955
#endif
6056
default: klass = cPKey; break;
6157
}
62-
obj = NewPKey(klass);
63-
SetPKey(obj, pkey);
58+
obj = rb_obj_alloc(klass);
59+
RTYPEDDATA_DATA(obj) = pkey;
6460
return obj;
6561
}
6662

@@ -516,16 +512,7 @@ DupPKeyPtr(VALUE obj)
516512
static VALUE
517513
ossl_pkey_alloc(VALUE klass)
518514
{
519-
EVP_PKEY *pkey;
520-
VALUE obj;
521-
522-
obj = NewPKey(klass);
523-
if (!(pkey = EVP_PKEY_new())) {
524-
ossl_raise(ePKeyError, NULL);
525-
}
526-
SetPKey(obj, pkey);
527-
528-
return obj;
515+
return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
529516
}
530517

531518
/*
@@ -544,6 +531,26 @@ ossl_pkey_initialize(VALUE self)
544531
return self;
545532
}
546533

534+
#ifdef HAVE_EVP_PKEY_DUP
535+
static VALUE
536+
ossl_pkey_initialize_copy(VALUE self, VALUE other)
537+
{
538+
EVP_PKEY *pkey, *pkey_other;
539+
540+
TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
541+
TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);
542+
if (pkey)
543+
rb_raise(rb_eTypeError, "pkey already initialized");
544+
if (pkey_other) {
545+
pkey = EVP_PKEY_dup(pkey_other);
546+
if (!pkey)
547+
ossl_raise(ePKeyError, "EVP_PKEY_dup");
548+
RTYPEDDATA_DATA(self) = pkey;
549+
}
550+
return self;
551+
}
552+
#endif
553+
547554
/*
548555
* call-seq:
549556
* pkey.oid -> string
@@ -1521,6 +1528,11 @@ Init_ossl_pkey(void)
15211528

15221529
rb_define_alloc_func(cPKey, ossl_pkey_alloc);
15231530
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
1531+
#ifdef HAVE_EVP_PKEY_DUP
1532+
rb_define_method(cPKey, "initialize_copy", ossl_pkey_initialize_copy, 1);
1533+
#else
1534+
rb_undef_method(cPKey, "initialize_copy");
1535+
#endif
15241536
rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
15251537
rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
15261538
rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);

ext/openssl/ossl_pkey.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,18 @@ extern VALUE cPKey;
1515
extern VALUE ePKeyError;
1616
extern const rb_data_type_t ossl_evp_pkey_type;
1717

18-
#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue)
19-
#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse)
20-
#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue)
18+
/* For ENGINE */
19+
#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern("private"), Qtrue)
20+
#define OSSL_PKEY_IS_PRIVATE(obj) (rb_attr_get((obj), rb_intern("private")) == Qtrue)
2121

22-
#define NewPKey(klass) \
23-
TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, 0)
24-
#define SetPKey(obj, pkey) do { \
25-
if (!(pkey)) { \
26-
rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \
27-
} \
28-
RTYPEDDATA_DATA(obj) = (pkey); \
29-
OSSL_PKEY_SET_PUBLIC(obj); \
30-
} while (0)
3122
#define GetPKey(obj, pkey) do {\
3223
TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
3324
if (!(pkey)) { \
3425
rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
3526
} \
3627
} while (0)
3728

29+
/* Takes ownership of the EVP_PKEY */
3830
VALUE ossl_pkey_new(EVP_PKEY *);
3931
void ossl_pkey_check_public_key(const EVP_PKEY *);
4032
EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);

ext/openssl/ossl_pkey_dh.c

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -72,53 +72,76 @@ static VALUE
7272
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
7373
{
7474
EVP_PKEY *pkey;
75+
int type;
7576
DH *dh;
76-
BIO *in;
77+
BIO *in = NULL;
7778
VALUE arg;
7879

79-
GetPKey(self, pkey);
80+
TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
81+
if (pkey)
82+
rb_raise(rb_eTypeError, "pkey already initialized");
83+
8084
/* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
8185
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
8286
dh = DH_new();
8387
if (!dh)
8488
ossl_raise(eDHError, "DH_new");
89+
goto legacy;
8590
}
86-
else {
87-
arg = ossl_to_der_if_possible(arg);
88-
in = ossl_obj2bio(&arg);
89-
dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
90-
if (!dh){
91-
OSSL_BIO_reset(in);
92-
dh = d2i_DHparams_bio(in, NULL);
93-
}
94-
BIO_free(in);
95-
if (!dh) {
96-
ossl_raise(eDHError, NULL);
97-
}
91+
92+
arg = ossl_to_der_if_possible(arg);
93+
in = ossl_obj2bio(&arg);
94+
95+
/*
96+
* On OpenSSL <= 1.1.1 and current versions of LibreSSL, the generic
97+
* routine does not support DER-encoded parameters
98+
*/
99+
dh = d2i_DHparams_bio(in, NULL);
100+
if (dh)
101+
goto legacy;
102+
OSSL_BIO_reset(in);
103+
104+
pkey = ossl_pkey_read_generic(in, Qnil);
105+
BIO_free(in);
106+
if (!pkey)
107+
ossl_raise(eDHError, "could not parse pkey");
108+
109+
type = EVP_PKEY_base_id(pkey);
110+
if (type != EVP_PKEY_DH) {
111+
EVP_PKEY_free(pkey);
112+
rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type));
98113
}
99-
if (!EVP_PKEY_assign_DH(pkey, dh)) {
100-
DH_free(dh);
101-
ossl_raise(eDHError, NULL);
114+
RTYPEDDATA_DATA(self) = pkey;
115+
return self;
116+
117+
legacy:
118+
BIO_free(in);
119+
pkey = EVP_PKEY_new();
120+
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
121+
EVP_PKEY_free(pkey);
122+
DH_free(dh);
123+
ossl_raise(eDHError, "EVP_PKEY_assign_DH");
102124
}
125+
RTYPEDDATA_DATA(self) = pkey;
103126
return self;
104127
}
105128

129+
#ifndef HAVE_EVP_PKEY_DUP
106130
static VALUE
107131
ossl_dh_initialize_copy(VALUE self, VALUE other)
108132
{
109133
EVP_PKEY *pkey;
110134
DH *dh, *dh_other;
111135
const BIGNUM *pub, *priv;
112136

113-
GetPKey(self, pkey);
114-
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
115-
ossl_raise(eDHError, "DH already initialized");
137+
TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
138+
if (pkey)
139+
rb_raise(rb_eTypeError, "pkey already initialized");
116140
GetDH(other, dh_other);
117141

118142
dh = DHparams_dup(dh_other);
119143
if (!dh)
120144
ossl_raise(eDHError, "DHparams_dup");
121-
EVP_PKEY_assign_DH(pkey, dh);
122145

123146
DH_get0_key(dh_other, &pub, &priv);
124147
if (pub) {
@@ -133,8 +156,16 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
133156
DH_set0_key(dh, pub2, priv2);
134157
}
135158

159+
pkey = EVP_PKEY_new();
160+
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
161+
EVP_PKEY_free(pkey);
162+
DH_free(dh);
163+
ossl_raise(eDHError, "EVP_PKEY_assign_DH");
164+
}
165+
RTYPEDDATA_DATA(self) = pkey;
136166
return self;
137167
}
168+
#endif
138169

139170
/*
140171
* call-seq:
@@ -378,7 +409,9 @@ Init_ossl_dh(void)
378409
*/
379410
cDH = rb_define_class_under(mPKey, "DH", cPKey);
380411
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
412+
#ifndef HAVE_EVP_PKEY_DUP
381413
rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1);
414+
#endif
382415
rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
383416
rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
384417
rb_define_method(cDH, "export", ossl_dh_export, 0);

ext/openssl/ossl_pkey_dsa.c

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -83,72 +83,91 @@ VALUE eDSAError;
8383
static VALUE
8484
ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
8585
{
86-
EVP_PKEY *pkey, *tmp;
87-
DSA *dsa = NULL;
88-
BIO *in;
86+
EVP_PKEY *pkey;
87+
DSA *dsa;
88+
BIO *in = NULL;
8989
VALUE arg, pass;
90+
int type;
91+
92+
TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
93+
if (pkey)
94+
rb_raise(rb_eTypeError, "pkey already initialized");
9095

91-
GetPKey(self, pkey);
9296
/* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
9397
rb_scan_args(argc, argv, "02", &arg, &pass);
9498
if (argc == 0) {
9599
dsa = DSA_new();
96100
if (!dsa)
97101
ossl_raise(eDSAError, "DSA_new");
102+
goto legacy;
98103
}
99-
else {
100-
pass = ossl_pem_passwd_value(pass);
101-
arg = ossl_to_der_if_possible(arg);
102-
in = ossl_obj2bio(&arg);
103-
104-
tmp = ossl_pkey_read_generic(in, pass);
105-
if (tmp) {
106-
if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA)
107-
rb_raise(eDSAError, "incorrect pkey type: %s",
108-
OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
109-
dsa = EVP_PKEY_get1_DSA(tmp);
110-
EVP_PKEY_free(tmp);
111-
}
112-
if (!dsa) {
113-
OSSL_BIO_reset(in);
114-
#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
115-
(d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u))
116-
dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
117-
#undef PEM_read_bio_DSAPublicKey
118-
}
119-
BIO_free(in);
120-
if (!dsa) {
121-
ossl_clear_error();
122-
ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
123-
}
124-
}
125-
if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
126-
DSA_free(dsa);
127-
ossl_raise(eDSAError, NULL);
104+
105+
pass = ossl_pem_passwd_value(pass);
106+
arg = ossl_to_der_if_possible(arg);
107+
in = ossl_obj2bio(&arg);
108+
109+
/* DER-encoded DSAPublicKey format isn't supported by the generic routine */
110+
dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey,
111+
PEM_STRING_DSA_PUBLIC,
112+
in, NULL, NULL, NULL);
113+
if (dsa)
114+
goto legacy;
115+
OSSL_BIO_reset(in);
116+
117+
pkey = ossl_pkey_read_generic(in, pass);
118+
BIO_free(in);
119+
if (!pkey)
120+
ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
121+
122+
type = EVP_PKEY_base_id(pkey);
123+
if (type != EVP_PKEY_DSA) {
124+
EVP_PKEY_free(pkey);
125+
rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
128126
}
127+
RTYPEDDATA_DATA(self) = pkey;
128+
return self;
129129

130+
legacy:
131+
BIO_free(in);
132+
pkey = EVP_PKEY_new();
133+
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
134+
EVP_PKEY_free(pkey);
135+
DSA_free(dsa);
136+
ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
137+
}
138+
RTYPEDDATA_DATA(self) = pkey;
130139
return self;
131140
}
132141

142+
#ifndef HAVE_EVP_PKEY_DUP
133143
static VALUE
134144
ossl_dsa_initialize_copy(VALUE self, VALUE other)
135145
{
136146
EVP_PKEY *pkey;
137147
DSA *dsa, *dsa_new;
138148

139-
GetPKey(self, pkey);
140-
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
141-
ossl_raise(eDSAError, "DSA already initialized");
149+
TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
150+
if (pkey)
151+
rb_raise(rb_eTypeError, "pkey already initialized");
142152
GetDSA(other, dsa);
143153

144-
dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa);
154+
dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey,
155+
(d2i_of_void *)d2i_DSAPrivateKey,
156+
(char *)dsa);
145157
if (!dsa_new)
146158
ossl_raise(eDSAError, "ASN1_dup");
147159

148-
EVP_PKEY_assign_DSA(pkey, dsa_new);
160+
pkey = EVP_PKEY_new();
161+
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
162+
EVP_PKEY_free(pkey);
163+
DSA_free(dsa_new);
164+
ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
165+
}
166+
RTYPEDDATA_DATA(self) = pkey;
149167

150168
return self;
151169
}
170+
#endif
152171

153172
/*
154173
* call-seq:
@@ -310,7 +329,9 @@ Init_ossl_dsa(void)
310329
cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
311330

312331
rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
332+
#ifndef HAVE_EVP_PKEY_DUP
313333
rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1);
334+
#endif
314335

315336
rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
316337
rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);

0 commit comments

Comments
 (0)