Skip to content

Commit 56f0d34

Browse files
committed
pkey: refactor #export/#to_pem and #to_der
Add ossl_pkey_export_traditional() and ossl_pkey_export_spki() helper functions, and use them. This reduces code duplication.
1 parent d963d4e commit 56f0d34

File tree

5 files changed

+114
-173
lines changed

5 files changed

+114
-173
lines changed

ext/openssl/ossl_pkey.c

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,52 @@ ossl_pkey_inspect(VALUE self)
341341
OBJ_nid2sn(nid));
342342
}
343343

344+
VALUE
345+
ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
346+
{
347+
EVP_PKEY *pkey;
348+
VALUE cipher, pass;
349+
const EVP_CIPHER *enc = NULL;
350+
BIO *bio;
351+
352+
GetPKey(self, pkey);
353+
rb_scan_args(argc, argv, "02", &cipher, &pass);
354+
if (!NIL_P(cipher)) {
355+
enc = ossl_evp_get_cipherbyname(cipher);
356+
pass = ossl_pem_passwd_value(pass);
357+
}
358+
359+
bio = BIO_new(BIO_s_mem());
360+
if (!bio)
361+
ossl_raise(ePKeyError, "BIO_new");
362+
if (to_der) {
363+
if (!i2d_PrivateKey_bio(bio, pkey)) {
364+
BIO_free(bio);
365+
ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
366+
}
367+
}
368+
else {
369+
#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
370+
if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
371+
ossl_pem_passwd_cb,
372+
(void *)pass)) {
373+
#else
374+
char pem_str[80];
375+
const char *aname;
376+
377+
EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth);
378+
snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname);
379+
if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio,
380+
pkey, enc, NULL, 0, ossl_pem_passwd_cb,
381+
(void *)pass)) {
382+
#endif
383+
BIO_free(bio);
384+
ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
385+
}
386+
}
387+
return ossl_membio2str(bio);
388+
}
389+
344390
static VALUE
345391
do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
346392
{
@@ -410,8 +456,8 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
410456
return do_pkcs8_export(argc, argv, self, 0);
411457
}
412458

413-
static VALUE
414-
do_spki_export(VALUE self, int to_der)
459+
VALUE
460+
ossl_pkey_export_spki(VALUE self, int to_der)
415461
{
416462
EVP_PKEY *pkey;
417463
BIO *bio;
@@ -444,7 +490,7 @@ do_spki_export(VALUE self, int to_der)
444490
static VALUE
445491
ossl_pkey_public_to_der(VALUE self)
446492
{
447-
return do_spki_export(self, 1);
493+
return ossl_pkey_export_spki(self, 1);
448494
}
449495

450496
/*
@@ -456,7 +502,7 @@ ossl_pkey_public_to_der(VALUE self)
456502
static VALUE
457503
ossl_pkey_public_to_pem(VALUE self)
458504
{
459-
return do_spki_export(self, 0);
505+
return ossl_pkey_export_spki(self, 0);
460506
}
461507

462508
/*

ext/openssl/ossl_pkey.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
4949
EVP_PKEY *GetPKeyPtr(VALUE);
5050
EVP_PKEY *DupPKeyPtr(VALUE);
5151
EVP_PKEY *GetPrivPKeyPtr(VALUE);
52+
53+
/*
54+
* Serializes _self_ in X.509 SubjectPublicKeyInfo format and returns the
55+
* resulting String. Sub-classes use this when overriding #to_der.
56+
*/
57+
VALUE ossl_pkey_export_spki(VALUE self, int to_der);
58+
/*
59+
* Serializes the private key _self_ in the traditional private key format
60+
* and returns the resulting String. Sub-classes use this when overriding
61+
* #to_der.
62+
*/
63+
VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self,
64+
int to_der);
65+
5266
void Init_ossl_pkey(void);
5367

5468
/*

ext/openssl/ossl_pkey_dsa.c

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -296,34 +296,12 @@ static VALUE
296296
ossl_dsa_export(int argc, VALUE *argv, VALUE self)
297297
{
298298
DSA *dsa;
299-
BIO *out;
300-
const EVP_CIPHER *ciph = NULL;
301-
VALUE cipher, pass, str;
302299

303300
GetDSA(self, dsa);
304-
rb_scan_args(argc, argv, "02", &cipher, &pass);
305-
if (!NIL_P(cipher)) {
306-
ciph = ossl_evp_get_cipherbyname(cipher);
307-
pass = ossl_pem_passwd_value(pass);
308-
}
309-
if (!(out = BIO_new(BIO_s_mem()))) {
310-
ossl_raise(eDSAError, NULL);
311-
}
312-
if (DSA_HAS_PRIVATE(dsa)) {
313-
if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0,
314-
ossl_pem_passwd_cb, (void *)pass)){
315-
BIO_free(out);
316-
ossl_raise(eDSAError, NULL);
317-
}
318-
} else {
319-
if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) {
320-
BIO_free(out);
321-
ossl_raise(eDSAError, NULL);
322-
}
323-
}
324-
str = ossl_membio2str(out);
325-
326-
return str;
301+
if (DSA_HAS_PRIVATE(dsa))
302+
return ossl_pkey_export_traditional(argc, argv, self, 0);
303+
else
304+
return ossl_pkey_export_spki(self, 0);
327305
}
328306

329307
/*
@@ -337,25 +315,12 @@ static VALUE
337315
ossl_dsa_to_der(VALUE self)
338316
{
339317
DSA *dsa;
340-
int (*i2d_func)(DSA *, unsigned char **);
341-
unsigned char *p;
342-
long len;
343-
VALUE str;
344318

345319
GetDSA(self, dsa);
346-
if(DSA_HAS_PRIVATE(dsa))
347-
i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey;
320+
if (DSA_HAS_PRIVATE(dsa))
321+
return ossl_pkey_export_traditional(0, NULL, self, 1);
348322
else
349-
i2d_func = i2d_DSA_PUBKEY;
350-
if((len = i2d_func(dsa, NULL)) <= 0)
351-
ossl_raise(eDSAError, NULL);
352-
str = rb_str_new(0, len);
353-
p = (unsigned char *)RSTRING_PTR(str);
354-
if(i2d_func(dsa, &p) < 0)
355-
ossl_raise(eDSAError, NULL);
356-
ossl_str_adjust(str, p);
357-
358-
return str;
323+
return ossl_pkey_export_spki(self, 1);
359324
}
360325

361326

ext/openssl/ossl_pkey_ec.c

Lines changed: 19 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
141141
static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
142142
{
143143
EVP_PKEY *pkey;
144-
EC_KEY *ec;
144+
EC_KEY *ec = NULL;
145145
VALUE arg, pass;
146146

147147
GetPKey(self, pkey);
@@ -378,66 +378,6 @@ static VALUE ossl_ec_key_is_private(VALUE self)
378378
return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse;
379379
}
380380

381-
static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
382-
{
383-
EC_KEY *ec;
384-
BIO *out;
385-
int i = -1;
386-
int private = 0;
387-
VALUE str;
388-
const EVP_CIPHER *cipher = NULL;
389-
390-
GetEC(self, ec);
391-
392-
if (EC_KEY_get0_public_key(ec) == NULL)
393-
ossl_raise(eECError, "can't export - no public key set");
394-
395-
if (EC_KEY_check_key(ec) != 1)
396-
ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
397-
398-
if (EC_KEY_get0_private_key(ec))
399-
private = 1;
400-
401-
if (!NIL_P(ciph)) {
402-
cipher = ossl_evp_get_cipherbyname(ciph);
403-
pass = ossl_pem_passwd_value(pass);
404-
}
405-
406-
if (!(out = BIO_new(BIO_s_mem())))
407-
ossl_raise(eECError, "BIO_new(BIO_s_mem())");
408-
409-
switch(format) {
410-
case EXPORT_PEM:
411-
if (private) {
412-
i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, ossl_pem_passwd_cb, (void *)pass);
413-
} else {
414-
i = PEM_write_bio_EC_PUBKEY(out, ec);
415-
}
416-
417-
break;
418-
case EXPORT_DER:
419-
if (private) {
420-
i = i2d_ECPrivateKey_bio(out, ec);
421-
} else {
422-
i = i2d_EC_PUBKEY_bio(out, ec);
423-
}
424-
425-
break;
426-
default:
427-
BIO_free(out);
428-
ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
429-
}
430-
431-
if (i != 1) {
432-
BIO_free(out);
433-
ossl_raise(eECError, "outlen=%d", i);
434-
}
435-
436-
str = ossl_membio2str(out);
437-
438-
return str;
439-
}
440-
441381
/*
442382
* call-seq:
443383
* key.export([cipher, pass_phrase]) => String
@@ -448,11 +388,16 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma
448388
* instance. Note that encryption will only be effective for a private key,
449389
* public keys will always be encoded in plain text.
450390
*/
451-
static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
391+
static VALUE
392+
ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
452393
{
453-
VALUE cipher, passwd;
454-
rb_scan_args(argc, argv, "02", &cipher, &passwd);
455-
return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM);
394+
EC_KEY *ec;
395+
396+
GetEC(self, ec);
397+
if (EC_KEY_get0_private_key(ec))
398+
return ossl_pkey_export_traditional(argc, argv, self, 0);
399+
else
400+
return ossl_pkey_export_spki(self, 0);
456401
}
457402

458403
/*
@@ -461,9 +406,16 @@ static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
461406
*
462407
* See the OpenSSL documentation for i2d_ECPrivateKey_bio()
463408
*/
464-
static VALUE ossl_ec_key_to_der(VALUE self)
409+
static VALUE
410+
ossl_ec_key_to_der(VALUE self)
465411
{
466-
return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
412+
EC_KEY *ec;
413+
414+
GetEC(self, ec);
415+
if (EC_KEY_get0_private_key(ec))
416+
return ossl_pkey_export_traditional(0, NULL, self, 1);
417+
else
418+
return ossl_pkey_export_spki(self, 1);
467419
}
468420

469421
/*

ext/openssl/ossl_pkey_rsa.c

Lines changed: 24 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
173173
static VALUE
174174
ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
175175
{
176-
EVP_PKEY *pkey;
177-
RSA *rsa;
176+
EVP_PKEY *pkey, *tmp;
177+
RSA *rsa = NULL;
178178
BIO *in;
179179
VALUE arg, pass;
180180

@@ -279,6 +279,21 @@ ossl_rsa_is_private(VALUE self)
279279
return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse;
280280
}
281281

282+
static int
283+
can_export_rsaprivatekey(VALUE self)
284+
{
285+
RSA *rsa;
286+
const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
287+
288+
GetRSA(self, rsa);
289+
290+
RSA_get0_key(rsa, &n, &e, &d);
291+
RSA_get0_factors(rsa, &p, &q);
292+
RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
293+
294+
return n && e && d && p && q && dmp1 && dmq1 && iqmp;
295+
}
296+
282297
/*
283298
* call-seq:
284299
* rsa.export([cipher, pass_phrase]) => PEM-format String
@@ -292,41 +307,10 @@ ossl_rsa_is_private(VALUE self)
292307
static VALUE
293308
ossl_rsa_export(int argc, VALUE *argv, VALUE self)
294309
{
295-
RSA *rsa;
296-
const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
297-
BIO *out;
298-
const EVP_CIPHER *ciph = NULL;
299-
VALUE cipher, pass, str;
300-
301-
GetRSA(self, rsa);
302-
303-
rb_scan_args(argc, argv, "02", &cipher, &pass);
304-
305-
if (!NIL_P(cipher)) {
306-
ciph = ossl_evp_get_cipherbyname(cipher);
307-
pass = ossl_pem_passwd_value(pass);
308-
}
309-
if (!(out = BIO_new(BIO_s_mem()))) {
310-
ossl_raise(eRSAError, NULL);
311-
}
312-
RSA_get0_key(rsa, &n, &e, &d);
313-
RSA_get0_factors(rsa, &p, &q);
314-
RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
315-
if (n && e && d && p && q && dmp1 && dmq1 && iqmp) {
316-
if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0,
317-
ossl_pem_passwd_cb, (void *)pass)) {
318-
BIO_free(out);
319-
ossl_raise(eRSAError, NULL);
320-
}
321-
} else {
322-
if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) {
323-
BIO_free(out);
324-
ossl_raise(eRSAError, NULL);
325-
}
326-
}
327-
str = ossl_membio2str(out);
328-
329-
return str;
310+
if (can_export_rsaprivatekey(self))
311+
return ossl_pkey_export_traditional(argc, argv, self, 0);
312+
else
313+
return ossl_pkey_export_spki(self, 0);
330314
}
331315

332316
/*
@@ -338,30 +322,10 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self)
338322
static VALUE
339323
ossl_rsa_to_der(VALUE self)
340324
{
341-
RSA *rsa;
342-
const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
343-
int (*i2d_func)(const RSA *, unsigned char **);
344-
unsigned char *ptr;
345-
long len;
346-
VALUE str;
347-
348-
GetRSA(self, rsa);
349-
RSA_get0_key(rsa, &n, &e, &d);
350-
RSA_get0_factors(rsa, &p, &q);
351-
RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
352-
if (n && e && d && p && q && dmp1 && dmq1 && iqmp)
353-
i2d_func = i2d_RSAPrivateKey;
325+
if (can_export_rsaprivatekey(self))
326+
return ossl_pkey_export_traditional(0, NULL, self, 1);
354327
else
355-
i2d_func = (int (*)(const RSA *, unsigned char **))i2d_RSA_PUBKEY;
356-
if((len = i2d_func(rsa, NULL)) <= 0)
357-
ossl_raise(eRSAError, NULL);
358-
str = rb_str_new(0, len);
359-
ptr = (unsigned char *)RSTRING_PTR(str);
360-
if(i2d_func(rsa, &ptr) < 0)
361-
ossl_raise(eRSAError, NULL);
362-
ossl_str_adjust(str, ptr);
363-
364-
return str;
328+
return ossl_pkey_export_spki(self, 1);
365329
}
366330

367331
/*

0 commit comments

Comments
 (0)