Skip to content

Commit d963d4e

Browse files
committed
pkey: refactor DER/PEM-encoded string parsing code
Export the flow used by OpenSSL::PKey.read and let the subclasses call it before attempting other formats.
1 parent cf92a3f commit d963d4e

File tree

5 files changed

+73
-77
lines changed

5 files changed

+73
-77
lines changed

ext/openssl/ossl_pkey.c

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,35 @@ ossl_pkey_new(EVP_PKEY *pkey)
136136
return obj;
137137
}
138138

139+
EVP_PKEY *
140+
ossl_pkey_read_generic(BIO *bio, VALUE pass)
141+
{
142+
void *ppass = (void *)pass;
143+
EVP_PKEY *pkey;
144+
145+
if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
146+
goto out;
147+
OSSL_BIO_reset(bio);
148+
if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
149+
goto out;
150+
OSSL_BIO_reset(bio);
151+
if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
152+
goto out;
153+
OSSL_BIO_reset(bio);
154+
/* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
155+
if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
156+
goto out;
157+
OSSL_BIO_reset(bio);
158+
if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
159+
goto out;
160+
OSSL_BIO_reset(bio);
161+
if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
162+
goto out;
163+
164+
out:
165+
return pkey;
166+
}
167+
139168
/*
140169
* call-seq:
141170
* OpenSSL::PKey.read(string [, pwd ]) -> PKey
@@ -160,33 +189,11 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
160189
VALUE data, pass;
161190

162191
rb_scan_args(argc, argv, "11", &data, &pass);
163-
pass = ossl_pem_passwd_value(pass);
164-
165192
bio = ossl_obj2bio(&data);
166-
if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
167-
goto ok;
168-
OSSL_BIO_reset(bio);
169-
if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
170-
goto ok;
171-
OSSL_BIO_reset(bio);
172-
if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
173-
goto ok;
174-
OSSL_BIO_reset(bio);
175-
/* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
176-
if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
177-
goto ok;
178-
OSSL_BIO_reset(bio);
179-
if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
180-
goto ok;
181-
OSSL_BIO_reset(bio);
182-
if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
183-
goto ok;
184-
185-
BIO_free(bio);
186-
ossl_raise(ePKeyError, "Could not parse PKey");
187-
188-
ok:
193+
pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
189194
BIO_free(bio);
195+
if (!pkey)
196+
ossl_raise(ePKeyError, "Could not parse PKey");
190197
return ossl_pkey_new(pkey);
191198
}
192199

ext/openssl/ossl_pkey.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ void ossl_generate_cb_stop(void *ptr);
4545

4646
VALUE ossl_pkey_new(EVP_PKEY *);
4747
void ossl_pkey_check_public_key(const EVP_PKEY *);
48+
EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
4849
EVP_PKEY *GetPKeyPtr(VALUE);
4950
EVP_PKEY *DupPKeyPtr(VALUE);
5051
EVP_PKEY *GetPrivPKeyPtr(VALUE);

ext/openssl/ossl_pkey_dsa.c

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -170,37 +170,34 @@ ossl_dsa_s_generate(VALUE klass, VALUE size)
170170
static VALUE
171171
ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
172172
{
173-
EVP_PKEY *pkey;
174-
DSA *dsa;
173+
EVP_PKEY *pkey, *tmp;
174+
DSA *dsa = NULL;
175175
BIO *in;
176176
VALUE arg, pass;
177177

178178
GetPKey(self, pkey);
179-
if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
179+
rb_scan_args(argc, argv, "02", &arg, &pass);
180+
if (argc == 0) {
180181
dsa = DSA_new();
182+
if (!dsa)
183+
ossl_raise(eDSAError, "DSA_new");
181184
}
182-
else if (RB_INTEGER_TYPE_P(arg)) {
183-
if (!(dsa = dsa_generate(NUM2INT(arg)))) {
184-
ossl_raise(eDSAError, NULL);
185-
}
185+
else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) {
186+
dsa = dsa_generate(NUM2INT(arg));
186187
}
187188
else {
188189
pass = ossl_pem_passwd_value(pass);
189190
arg = ossl_to_der_if_possible(arg);
190191
in = ossl_obj2bio(&arg);
191-
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
192-
if (!dsa) {
193-
OSSL_BIO_reset(in);
194-
dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
195-
}
196-
if (!dsa) {
197-
OSSL_BIO_reset(in);
198-
dsa = d2i_DSAPrivateKey_bio(in, NULL);
199-
}
200-
if (!dsa) {
201-
OSSL_BIO_reset(in);
202-
dsa = d2i_DSA_PUBKEY_bio(in, NULL);
203-
}
192+
193+
tmp = ossl_pkey_read_generic(in, pass);
194+
if (tmp) {
195+
if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA)
196+
rb_raise(eDSAError, "incorrect pkey type: %s",
197+
OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
198+
dsa = EVP_PKEY_get1_DSA(tmp);
199+
EVP_PKEY_free(tmp);
200+
}
204201
if (!dsa) {
205202
OSSL_BIO_reset(in);
206203
#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \

ext/openssl/ossl_pkey_ec.c

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -162,24 +162,17 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
162162
} else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
163163
ec = ec_key_new_from_group(arg);
164164
} else {
165-
BIO *in;
166-
167-
pass = ossl_pem_passwd_value(pass);
168-
in = ossl_obj2bio(&arg);
169-
170-
ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
171-
if (!ec) {
172-
OSSL_BIO_reset(in);
173-
ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass);
174-
}
175-
if (!ec) {
176-
OSSL_BIO_reset(in);
177-
ec = d2i_ECPrivateKey_bio(in, NULL);
178-
}
179-
if (!ec) {
180-
OSSL_BIO_reset(in);
181-
ec = d2i_EC_PUBKEY_bio(in, NULL);
182-
}
165+
BIO *in = ossl_obj2bio(&arg);
166+
EVP_PKEY *tmp;
167+
pass = ossl_pem_passwd_value(pass);
168+
tmp = ossl_pkey_read_generic(in, pass);
169+
if (tmp) {
170+
if (EVP_PKEY_base_id(tmp) != EVP_PKEY_EC)
171+
rb_raise(eECError, "incorrect pkey type: %s",
172+
OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
173+
ec = EVP_PKEY_get1_EC_KEY(tmp);
174+
EVP_PKEY_free(tmp);
175+
}
183176
BIO_free(in);
184177

185178
if (!ec) {

ext/openssl/ossl_pkey_rsa.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
179179
VALUE arg, pass;
180180

181181
GetPKey(self, pkey);
182-
if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
182+
rb_scan_args(argc, argv, "02", &arg, &pass);
183+
if (argc == 0) {
183184
rsa = RSA_new();
184185
if (!rsa)
185186
ossl_raise(eRSAError, "RSA_new");
@@ -191,19 +192,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
191192
pass = ossl_pem_passwd_value(pass);
192193
arg = ossl_to_der_if_possible(arg);
193194
in = ossl_obj2bio(&arg);
194-
rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
195-
if (!rsa) {
196-
OSSL_BIO_reset(in);
197-
rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL);
198-
}
199-
if (!rsa) {
200-
OSSL_BIO_reset(in);
201-
rsa = d2i_RSAPrivateKey_bio(in, NULL);
202-
}
203-
if (!rsa) {
204-
OSSL_BIO_reset(in);
205-
rsa = d2i_RSA_PUBKEY_bio(in, NULL);
206-
}
195+
196+
tmp = ossl_pkey_read_generic(in, pass);
197+
if (tmp) {
198+
if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA)
199+
rb_raise(eRSAError, "incorrect pkey type: %s",
200+
OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
201+
rsa = EVP_PKEY_get1_RSA(tmp);
202+
EVP_PKEY_free(tmp);
203+
}
207204
if (!rsa) {
208205
OSSL_BIO_reset(in);
209206
rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
@@ -214,6 +211,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
214211
}
215212
BIO_free(in);
216213
if (!rsa) {
214+
ossl_clear_error();
217215
ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
218216
}
219217
}

0 commit comments

Comments
 (0)