Skip to content

Commit 74f6c61

Browse files
committed
pkey: allocate EVP_PKEY on #initialize
Allocate an EVP_PKEY when the content is ready: when #initialize or #initialize_copy is called, rather than when a T_DATA is allocated. This is more natural because the lower level API has been deprecated and an EVP_PKEY is becoming the minimum unit of handling keys.
1 parent 316cb2a commit 74f6c61

File tree

6 files changed

+218
-163
lines changed

6 files changed

+218
-163
lines changed

ext/openssl/ossl_pkey.c

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ pkey_new0(VALUE arg)
5555
#endif
5656
default: klass = cPKey; break;
5757
}
58-
obj = NewPKey(klass);
59-
SetPKey(obj, pkey);
58+
obj = rb_obj_alloc(klass);
59+
RTYPEDDATA_DATA(obj) = pkey;
6060
return obj;
6161
}
6262

@@ -472,16 +472,7 @@ DupPKeyPtr(VALUE obj)
472472
static VALUE
473473
ossl_pkey_alloc(VALUE klass)
474474
{
475-
EVP_PKEY *pkey;
476-
VALUE obj;
477-
478-
obj = NewPKey(klass);
479-
if (!(pkey = EVP_PKEY_new())) {
480-
ossl_raise(ePKeyError, NULL);
481-
}
482-
SetPKey(obj, pkey);
483-
484-
return obj;
475+
return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
485476
}
486477

487478
/*

ext/openssl/ossl_pkey.h

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,10 @@ 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)) { \

ext/openssl/ossl_pkey_dh.c

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -72,34 +72,57 @@ 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

@@ -110,15 +133,14 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
110133
DH *dh, *dh_other;
111134
const BIGNUM *pub, *priv;
112135

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

118141
dh = DHparams_dup(dh_other);
119142
if (!dh)
120143
ossl_raise(eDHError, "DHparams_dup");
121-
EVP_PKEY_assign_DH(pkey, dh);
122144

123145
DH_get0_key(dh_other, &pub, &priv);
124146
if (pub) {
@@ -133,6 +155,13 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
133155
DH_set0_key(dh, pub2, priv2);
134156
}
135157

158+
pkey = EVP_PKEY_new();
159+
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
160+
EVP_PKEY_free(pkey);
161+
DH_free(dh);
162+
ossl_raise(eDHError, "EVP_PKEY_assign_DH");
163+
}
164+
RTYPEDDATA_DATA(self) = pkey;
136165
return self;
137166
}
138167

ext/openssl/ossl_pkey_dsa.c

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -83,50 +83,59 @@ 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

@@ -136,16 +145,24 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other)
136145
EVP_PKEY *pkey;
137146
DSA *dsa, *dsa_new;
138147

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

144-
dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa);
153+
dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey,
154+
(d2i_of_void *)d2i_DSAPrivateKey,
155+
(char *)dsa);
145156
if (!dsa_new)
146157
ossl_raise(eDSAError, "ASN1_dup");
147158

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

150167
return self;
151168
}

0 commit comments

Comments
 (0)