cd5466
From 8b8e1d7f9b6b5a335864bbd0716df2af1ec41d91 Mon Sep 17 00:00:00 2001
cd5466
From: Kazuki Yamaguchi <k@rhe.jp>
cd5466
Date: Thu, 16 Mar 2017 16:06:53 +0900
cd5466
Subject: [PATCH 1/5] pkey: simplify ossl_pkey_new()
cd5466
cd5466
ossl_{rsa,dsa,dh,ec}_new() called from this function are not used
cd5466
anywhere else. Inline them into pkey_new0() and reduce code
cd5466
duplication.
cd5466
---
cd5466
 ext/openssl/ossl_pkey.c     | 22 +++++++++-------------
cd5466
 ext/openssl/ossl_pkey.h     |  3 ---
cd5466
 ext/openssl/ossl_pkey_dh.c  | 21 ---------------------
cd5466
 ext/openssl/ossl_pkey_dsa.c | 21 ---------------------
cd5466
 ext/openssl/ossl_pkey_ec.c  | 20 --------------------
cd5466
 ext/openssl/ossl_pkey_rsa.c | 22 ----------------------
cd5466
 6 files changed, 9 insertions(+), 100 deletions(-)
cd5466
cd5466
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
cd5466
index 23204087ac..c6dbf57272 100644
cd5466
--- a/ext/openssl/ossl_pkey.c
cd5466
+++ b/ext/openssl/ossl_pkey.c
cd5466
@@ -95,7 +95,7 @@ const rb_data_type_t ossl_evp_pkey_type = {
cd5466
 static VALUE
cd5466
 pkey_new0(EVP_PKEY *pkey)
cd5466
 {
cd5466
-    VALUE obj;
cd5466
+    VALUE klass, obj;
cd5466
     int type;
cd5466
 
cd5466
     if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
cd5466
@@ -103,26 +103,22 @@ pkey_new0(EVP_PKEY *pkey)
cd5466
 
cd5466
     switch (type) {
cd5466
 #if !defined(OPENSSL_NO_RSA)
cd5466
-    case EVP_PKEY_RSA:
cd5466
-	return ossl_rsa_new(pkey);
cd5466
+      case EVP_PKEY_RSA: klass = cRSA; break;
cd5466
 #endif
cd5466
 #if !defined(OPENSSL_NO_DSA)
cd5466
-    case EVP_PKEY_DSA:
cd5466
-	return ossl_dsa_new(pkey);
cd5466
+      case EVP_PKEY_DSA: klass = cDSA; break;
cd5466
 #endif
cd5466
 #if !defined(OPENSSL_NO_DH)
cd5466
-    case EVP_PKEY_DH:
cd5466
-	return ossl_dh_new(pkey);
cd5466
+      case EVP_PKEY_DH:  klass = cDH; break;
cd5466
 #endif
cd5466
 #if !defined(OPENSSL_NO_EC)
cd5466
-    case EVP_PKEY_EC:
cd5466
-	return ossl_ec_new(pkey);
cd5466
+      case EVP_PKEY_EC:  klass = cEC; break;
cd5466
 #endif
cd5466
-    default:
cd5466
-	obj = NewPKey(cPKey);
cd5466
-	SetPKey(obj, pkey);
cd5466
-	return obj;
cd5466
+      default:           klass = cPKey; break;
cd5466
     }
cd5466
+    obj = NewPKey(klass);
cd5466
+    SetPKey(obj, pkey);
cd5466
+    return obj;
cd5466
 }
cd5466
 
cd5466
 VALUE
cd5466
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
cd5466
index 0db59305f7..e363a261c2 100644
cd5466
--- a/ext/openssl/ossl_pkey.h
cd5466
+++ b/ext/openssl/ossl_pkey.h
cd5466
@@ -56,7 +56,6 @@ void Init_ossl_pkey(void);
cd5466
 extern VALUE cRSA;
cd5466
 extern VALUE eRSAError;
cd5466
 
cd5466
-VALUE ossl_rsa_new(EVP_PKEY *);
cd5466
 void Init_ossl_rsa(void);
cd5466
 
cd5466
 /*
cd5466
@@ -65,7 +64,6 @@ void Init_ossl_rsa(void);
cd5466
 extern VALUE cDSA;
cd5466
 extern VALUE eDSAError;
cd5466
 
cd5466
-VALUE ossl_dsa_new(EVP_PKEY *);
cd5466
 void Init_ossl_dsa(void);
cd5466
 
cd5466
 /*
cd5466
@@ -74,7 +72,6 @@ void Init_ossl_dsa(void);
cd5466
 extern VALUE cDH;
cd5466
 extern VALUE eDHError;
cd5466
 
cd5466
-VALUE ossl_dh_new(EVP_PKEY *);
cd5466
 void Init_ossl_dh(void);
cd5466
 
cd5466
 /*
cd5466
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
cd5466
index bf4e3f9322..dff69cfc33 100644
cd5466
--- a/ext/openssl/ossl_pkey_dh.c
cd5466
+++ b/ext/openssl/ossl_pkey_dh.c
cd5466
@@ -54,27 +54,6 @@ dh_instance(VALUE klass, DH *dh)
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
-VALUE
cd5466
-ossl_dh_new(EVP_PKEY *pkey)
cd5466
-{
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!pkey) {
cd5466
-	obj = dh_instance(cDH, DH_new());
cd5466
-    } else {
cd5466
-	obj = NewPKey(cDH);
cd5466
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) {
cd5466
-	    ossl_raise(rb_eTypeError, "Not a DH key!");
cd5466
-	}
cd5466
-	SetPKey(obj, pkey);
cd5466
-    }
cd5466
-    if (obj == Qfalse) {
cd5466
-	ossl_raise(eDHError, NULL);
cd5466
-    }
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Private
cd5466
  */
cd5466
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
cd5466
index 431c20e05c..e9be9ac482 100644
cd5466
--- a/ext/openssl/ossl_pkey_dsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_dsa.c
cd5466
@@ -68,27 +68,6 @@ dsa_instance(VALUE klass, DSA *dsa)
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
-VALUE
cd5466
-ossl_dsa_new(EVP_PKEY *pkey)
cd5466
-{
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!pkey) {
cd5466
-	obj = dsa_instance(cDSA, DSA_new());
cd5466
-    } else {
cd5466
-	obj = NewPKey(cDSA);
cd5466
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) {
cd5466
-	    ossl_raise(rb_eTypeError, "Not a DSA key!");
cd5466
-	}
cd5466
-	SetPKey(obj, pkey);
cd5466
-    }
cd5466
-    if (obj == Qfalse) {
cd5466
-	ossl_raise(eDSAError, NULL);
cd5466
-    }
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Private
cd5466
  */
cd5466
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
cd5466
index fc2bc6c815..eabf495f19 100644
cd5466
--- a/ext/openssl/ossl_pkey_ec.c
cd5466
+++ b/ext/openssl/ossl_pkey_ec.c
cd5466
@@ -84,26 +84,6 @@ static VALUE ec_instance(VALUE klass, EC_KEY *ec)
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
-VALUE ossl_ec_new(EVP_PKEY *pkey)
cd5466
-{
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!pkey) {
cd5466
-	obj = ec_instance(cEC, EC_KEY_new());
cd5466
-    } else {
cd5466
-	obj = NewPKey(cEC);
cd5466
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
cd5466
-	    ossl_raise(rb_eTypeError, "Not a EC key!");
cd5466
-	}
cd5466
-	SetPKey(obj, pkey);
cd5466
-    }
cd5466
-    if (obj == Qfalse) {
cd5466
-	ossl_raise(eECError, NULL);
cd5466
-    }
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String
cd5466
  * representing an OID.
cd5466
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
cd5466
index 761866c66a..c1ae44fe40 100644
cd5466
--- a/ext/openssl/ossl_pkey_rsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_rsa.c
cd5466
@@ -69,28 +69,6 @@ rsa_instance(VALUE klass, RSA *rsa)
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
-VALUE
cd5466
-ossl_rsa_new(EVP_PKEY *pkey)
cd5466
-{
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!pkey) {
cd5466
-	obj = rsa_instance(cRSA, RSA_new());
cd5466
-    }
cd5466
-    else {
cd5466
-	obj = NewPKey(cRSA);
cd5466
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
cd5466
-	    ossl_raise(rb_eTypeError, "Not a RSA key!");
cd5466
-	}
cd5466
-	SetPKey(obj, pkey);
cd5466
-    }
cd5466
-    if (obj == Qfalse) {
cd5466
-	ossl_raise(eRSAError, NULL);
cd5466
-    }
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Private
cd5466
  */
cd5466
-- 
cd5466
2.32.0
cd5466
cd5466
cd5466
From 2b0d259ef7aae707922996d305675a68dad27abd Mon Sep 17 00:00:00 2001
cd5466
From: Kazuki Yamaguchi <k@rhe.jp>
cd5466
Date: Thu, 16 Mar 2017 16:09:35 +0900
cd5466
Subject: [PATCH 2/5] pkey: inline {rsa,dsa,dh,ec}_instance()
cd5466
cd5466
Merge the code into the callers so that the wrapping Ruby object is
cd5466
allocated before the raw key object is allocated. This prevents possible
cd5466
memory leak on Ruby object allocation failure, and also reduces the
cd5466
lines of code.
cd5466
---
cd5466
 ext/openssl/ossl_pkey_dh.c  | 63 ++++++++++++----------------------
cd5466
 ext/openssl/ossl_pkey_dsa.c | 68 ++++++++++++++-----------------------
cd5466
 ext/openssl/ossl_pkey_ec.c  | 34 ++++---------------
cd5466
 ext/openssl/ossl_pkey_rsa.c | 67 +++++++++++++-----------------------
cd5466
 4 files changed, 76 insertions(+), 156 deletions(-)
cd5466
cd5466
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
cd5466
index dff69cfc33..bc50e5566b 100644
cd5466
--- a/ext/openssl/ossl_pkey_dh.c
cd5466
+++ b/ext/openssl/ossl_pkey_dh.c
cd5466
@@ -29,31 +29,6 @@
cd5466
 VALUE cDH;
cd5466
 VALUE eDHError;
cd5466
 
cd5466
-/*
cd5466
- * Public
cd5466
- */
cd5466
-static VALUE
cd5466
-dh_instance(VALUE klass, DH *dh)
cd5466
-{
cd5466
-    EVP_PKEY *pkey;
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!dh) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    obj = NewPKey(klass);
cd5466
-    if (!(pkey = EVP_PKEY_new())) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    if (!EVP_PKEY_assign_DH(pkey, dh)) {
cd5466
-	EVP_PKEY_free(pkey);
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    SetPKey(obj, pkey);
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Private
cd5466
  */
cd5466
@@ -84,7 +59,7 @@ dh_generate(int size, int gen)
cd5466
     if (!dh || !cb) {
cd5466
 	DH_free(dh);
cd5466
 	BN_GENCB_free(cb);
cd5466
-	return NULL;
cd5466
+        ossl_raise(eDHError, "malloc failure");
cd5466
     }
cd5466
 
cd5466
     if (rb_block_given_p())
cd5466
@@ -110,12 +85,12 @@ dh_generate(int size, int gen)
cd5466
 	    ossl_clear_error();
cd5466
 	    rb_jump_tag(cb_arg.state);
cd5466
 	}
cd5466
-	return NULL;
cd5466
+        ossl_raise(eDHError, "DH_generate_parameters_ex");
cd5466
     }
cd5466
 
cd5466
     if (!DH_generate_key(dh)) {
cd5466
         DH_free(dh);
cd5466
-        return NULL;
cd5466
+        ossl_raise(eDHError, "DH_generate_key");
cd5466
     }
cd5466
 
cd5466
     return dh;
cd5466
@@ -136,6 +111,7 @@ dh_generate(int size, int gen)
cd5466
 static VALUE
cd5466
 ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
cd5466
 {
cd5466
+    EVP_PKEY *pkey;
cd5466
     DH *dh ;
cd5466
     int g = 2;
cd5466
     VALUE size, gen, obj;
cd5466
@@ -143,13 +119,14 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
cd5466
     if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
cd5466
 	g = NUM2INT(gen);
cd5466
     }
cd5466
+    obj = rb_obj_alloc(klass);
cd5466
+    GetPKey(obj, pkey);
cd5466
+
cd5466
     dh = dh_generate(NUM2INT(size), g);
cd5466
-    obj = dh_instance(klass, dh);
cd5466
-    if (obj == Qfalse) {
cd5466
-	DH_free(dh);
cd5466
-	ossl_raise(eDHError, NULL);
cd5466
+    if (!EVP_PKEY_assign_DH(pkey, dh)) {
cd5466
+        DH_free(dh);
cd5466
+        ossl_raise(eDHError, "EVP_PKEY_assign_DH");
cd5466
     }
cd5466
-
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
@@ -195,9 +172,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
cd5466
 	if (!NIL_P(gen)) {
cd5466
 	    g = NUM2INT(gen);
cd5466
 	}
cd5466
-	if (!(dh = dh_generate(NUM2INT(arg), g))) {
cd5466
-	    ossl_raise(eDHError, NULL);
cd5466
-	}
cd5466
+        dh = dh_generate(NUM2INT(arg), g);
cd5466
     }
cd5466
     else {
cd5466
 	arg = ossl_to_der_if_possible(arg);
cd5466
@@ -434,17 +409,21 @@ ossl_dh_to_text(VALUE self)
cd5466
 static VALUE
cd5466
 ossl_dh_to_public_key(VALUE self)
cd5466
 {
cd5466
+    EVP_PKEY *pkey;
cd5466
     DH *orig_dh, *dh;
cd5466
     VALUE obj;
cd5466
 
cd5466
+    obj = rb_obj_alloc(rb_obj_class(self));
cd5466
+    GetPKey(obj, pkey);
cd5466
+
cd5466
     GetDH(self, orig_dh);
cd5466
-    dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */
cd5466
-    obj = dh_instance(rb_obj_class(self), dh);
cd5466
-    if (obj == Qfalse) {
cd5466
-	DH_free(dh);
cd5466
-	ossl_raise(eDHError, NULL);
cd5466
+    dh = DHparams_dup(orig_dh);
cd5466
+    if (!dh)
cd5466
+        ossl_raise(eDHError, "DHparams_dup");
cd5466
+    if (!EVP_PKEY_assign_DH(pkey, dh)) {
cd5466
+        DH_free(dh);
cd5466
+        ossl_raise(eDHError, "EVP_PKEY_assign_DH");
cd5466
     }
cd5466
-
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
cd5466
index e9be9ac482..c907f31c19 100644
cd5466
--- a/ext/openssl/ossl_pkey_dsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_dsa.c
cd5466
@@ -43,31 +43,6 @@ DSA_PRIVATE(VALUE obj, DSA *dsa)
cd5466
 VALUE cDSA;
cd5466
 VALUE eDSAError;
cd5466
 
cd5466
-/*
cd5466
- * Public
cd5466
- */
cd5466
-static VALUE
cd5466
-dsa_instance(VALUE klass, DSA *dsa)
cd5466
-{
cd5466
-    EVP_PKEY *pkey;
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!dsa) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    obj = NewPKey(klass);
cd5466
-    if (!(pkey = EVP_PKEY_new())) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
cd5466
-	EVP_PKEY_free(pkey);
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    SetPKey(obj, pkey);
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Private
cd5466
  */
cd5466
@@ -100,9 +75,9 @@ dsa_generate(int size)
cd5466
     unsigned long h;
cd5466
 
cd5466
     if (!dsa || !cb) {
cd5466
-	DSA_free(dsa);
cd5466
-	BN_GENCB_free(cb);
cd5466
-	return NULL;
cd5466
+        DSA_free(dsa);
cd5466
+        BN_GENCB_free(cb);
cd5466
+        ossl_raise(eDSAError, "malloc failure");
cd5466
     }
cd5466
 
cd5466
     if (rb_block_given_p())
cd5466
@@ -132,12 +107,12 @@ dsa_generate(int size)
cd5466
 	    ossl_clear_error();
cd5466
 	    rb_jump_tag(cb_arg.state);
cd5466
 	}
cd5466
-	return NULL;
cd5466
+        ossl_raise(eDSAError, "DSA_generate_parameters_ex");
cd5466
     }
cd5466
 
cd5466
     if (!DSA_generate_key(dsa)) {
cd5466
-	DSA_free(dsa);
cd5466
-	return NULL;
cd5466
+        DSA_free(dsa);
cd5466
+        ossl_raise(eDSAError, "DSA_generate_key");
cd5466
     }
cd5466
 
cd5466
     return dsa;
cd5466
@@ -157,14 +132,18 @@ dsa_generate(int size)
cd5466
 static VALUE
cd5466
 ossl_dsa_s_generate(VALUE klass, VALUE size)
cd5466
 {
cd5466
-    DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */
cd5466
-    VALUE obj = dsa_instance(klass, dsa);
cd5466
+    EVP_PKEY *pkey;
cd5466
+    DSA *dsa;
cd5466
+    VALUE obj;
cd5466
 
cd5466
-    if (obj == Qfalse) {
cd5466
-	DSA_free(dsa);
cd5466
-	ossl_raise(eDSAError, NULL);
cd5466
-    }
cd5466
+    obj = rb_obj_alloc(klass);
cd5466
+    GetPKey(obj, pkey);
cd5466
 
cd5466
+    dsa = dsa_generate(NUM2INT(size));
cd5466
+    if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
cd5466
+        DSA_free(dsa);
cd5466
+        ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
cd5466
+    }
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
@@ -460,20 +439,23 @@ ossl_dsa_to_text(VALUE self)
cd5466
 static VALUE
cd5466
 ossl_dsa_to_public_key(VALUE self)
cd5466
 {
cd5466
-    EVP_PKEY *pkey;
cd5466
+    EVP_PKEY *pkey, *pkey_new;
cd5466
     DSA *dsa;
cd5466
     VALUE obj;
cd5466
 
cd5466
     GetPKeyDSA(self, pkey);
cd5466
-    /* err check performed by dsa_instance */
cd5466
+    obj = rb_obj_alloc(rb_obj_class(self));
cd5466
+    GetPKey(obj, pkey_new);
cd5466
+
cd5466
 #define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \
cd5466
 	(i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa))
cd5466
     dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey));
cd5466
 #undef DSAPublicKey_dup
cd5466
-    obj = dsa_instance(rb_obj_class(self), dsa);
cd5466
-    if (obj == Qfalse) {
cd5466
-	DSA_free(dsa);
cd5466
-	ossl_raise(eDSAError, NULL);
cd5466
+    if (!dsa)
cd5466
+        ossl_raise(eDSAError, "DSAPublicKey_dup");
cd5466
+    if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) {
cd5466
+        DSA_free(dsa);
cd5466
+        ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
cd5466
     }
cd5466
     return obj;
cd5466
 }
cd5466
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
cd5466
index eabf495f19..aec9d1e60f 100644
cd5466
--- a/ext/openssl/ossl_pkey_ec.c
cd5466
+++ b/ext/openssl/ossl_pkey_ec.c
cd5466
@@ -63,27 +63,6 @@ static ID id_i_group;
cd5466
 static VALUE ec_group_new(const EC_GROUP *group);
cd5466
 static VALUE ec_point_new(const EC_POINT *point, const EC_GROUP *group);
cd5466
 
cd5466
-static VALUE ec_instance(VALUE klass, EC_KEY *ec)
cd5466
-{
cd5466
-    EVP_PKEY *pkey;
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!ec) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    obj = NewPKey(klass);
cd5466
-    if (!(pkey = EVP_PKEY_new())) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
cd5466
-	EVP_PKEY_free(pkey);
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    SetPKey(obj, pkey);
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String
cd5466
  * representing an OID.
cd5466
@@ -130,17 +109,18 @@ ec_key_new_from_group(VALUE arg)
cd5466
 static VALUE
cd5466
 ossl_ec_key_s_generate(VALUE klass, VALUE arg)
cd5466
 {
cd5466
+    EVP_PKEY *pkey;
cd5466
     EC_KEY *ec;
cd5466
     VALUE obj;
cd5466
 
cd5466
-    ec = ec_key_new_from_group(arg);
cd5466
+    obj = rb_obj_alloc(klass);
cd5466
+    GetPKey(obj, pkey);
cd5466
 
cd5466
-    obj = ec_instance(klass, ec);
cd5466
-    if (obj == Qfalse) {
cd5466
-	EC_KEY_free(ec);
cd5466
-	ossl_raise(eECError, NULL);
cd5466
+    ec = ec_key_new_from_group(arg);
cd5466
+    if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
cd5466
+        EC_KEY_free(ec);
cd5466
+        ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
cd5466
     }
cd5466
-
cd5466
     if (!EC_KEY_generate_key(ec))
cd5466
 	ossl_raise(eECError, "EC_KEY_generate_key");
cd5466
 
cd5466
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
cd5466
index c1ae44fe40..fbdb9c8960 100644
cd5466
--- a/ext/openssl/ossl_pkey_rsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_rsa.c
cd5466
@@ -44,31 +44,6 @@ RSA_PRIVATE(VALUE obj, RSA *rsa)
cd5466
 VALUE cRSA;
cd5466
 VALUE eRSAError;
cd5466
 
cd5466
-/*
cd5466
- * Public
cd5466
- */
cd5466
-static VALUE
cd5466
-rsa_instance(VALUE klass, RSA *rsa)
cd5466
-{
cd5466
-    EVP_PKEY *pkey;
cd5466
-    VALUE obj;
cd5466
-
cd5466
-    if (!rsa) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    obj = NewPKey(klass);
cd5466
-    if (!(pkey = EVP_PKEY_new())) {
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
cd5466
-	EVP_PKEY_free(pkey);
cd5466
-	return Qfalse;
cd5466
-    }
cd5466
-    SetPKey(obj, pkey);
cd5466
-
cd5466
-    return obj;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  * Private
cd5466
  */
cd5466
@@ -102,7 +77,7 @@ rsa_generate(int size, unsigned long exp)
cd5466
 	RSA_free(rsa);
cd5466
 	BN_free(e);
cd5466
 	BN_GENCB_free(cb);
cd5466
-	return NULL;
cd5466
+        ossl_raise(eRSAError, "malloc failure");
cd5466
     }
cd5466
     for (i = 0; i < (int)sizeof(exp) * 8; ++i) {
cd5466
 	if (exp & (1UL << i)) {
cd5466
@@ -110,7 +85,7 @@ rsa_generate(int size, unsigned long exp)
cd5466
 		BN_free(e);
cd5466
 		RSA_free(rsa);
cd5466
 		BN_GENCB_free(cb);
cd5466
-		return NULL;
cd5466
+                ossl_raise(eRSAError, "BN_set_bit");
cd5466
 	    }
cd5466
 	}
cd5466
     }
cd5466
@@ -139,7 +114,7 @@ rsa_generate(int size, unsigned long exp)
cd5466
 	    ossl_clear_error();
cd5466
 	    rb_jump_tag(cb_arg.state);
cd5466
 	}
cd5466
-	return NULL;
cd5466
+        ossl_raise(eRSAError, "RSA_generate_key_ex");
cd5466
     }
cd5466
 
cd5466
     return rsa;
cd5466
@@ -158,26 +133,26 @@ static VALUE
cd5466
 ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
cd5466
 {
cd5466
 /* why does this method exist?  why can't initialize take an optional exponent? */
cd5466
+    EVP_PKEY *pkey;
cd5466
     RSA *rsa;
cd5466
     VALUE size, exp;
cd5466
     VALUE obj;
cd5466
 
cd5466
     rb_scan_args(argc, argv, "11", &size, &exp);
cd5466
+    obj = rb_obj_alloc(klass);
cd5466
+    GetPKey(obj, pkey);
cd5466
 
cd5466
-    rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); /* err handled by rsa_instance */
cd5466
-    obj = rsa_instance(klass, rsa);
cd5466
-
cd5466
-    if (obj == Qfalse) {
cd5466
-	RSA_free(rsa);
cd5466
-	ossl_raise(eRSAError, NULL);
cd5466
+    rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp));
cd5466
+    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
cd5466
+        RSA_free(rsa);
cd5466
+        ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
cd5466
     }
cd5466
-
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
  * call-seq:
cd5466
- *   RSA.new(key_size)                 => RSA instance
cd5466
+ *   RSA.new(size [, exponent])        => RSA instance
cd5466
  *   RSA.new(encoded_key)              => RSA instance
cd5466
  *   RSA.new(encoded_key, pass_phrase) => RSA instance
cd5466
  *
cd5466
@@ -206,10 +181,11 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
cd5466
     GetPKey(self, pkey);
cd5466
     if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
cd5466
 	rsa = RSA_new();
cd5466
+        if (!rsa)
cd5466
+            ossl_raise(eRSAError, "RSA_new");
cd5466
     }
cd5466
     else if (RB_INTEGER_TYPE_P(arg)) {
cd5466
 	rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass));
cd5466
-	if (!rsa) ossl_raise(eRSAError, NULL);
cd5466
     }
cd5466
     else {
cd5466
 	pass = ossl_pem_passwd_value(pass);
cd5466
@@ -243,7 +219,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
cd5466
     }
cd5466
     if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
cd5466
 	RSA_free(rsa);
cd5466
-	ossl_raise(eRSAError, NULL);
cd5466
+	ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
cd5466
     }
cd5466
 
cd5466
     return self;
cd5466
@@ -787,17 +763,20 @@ ossl_rsa_to_text(VALUE self)
cd5466
 static VALUE
cd5466
 ossl_rsa_to_public_key(VALUE self)
cd5466
 {
cd5466
-    EVP_PKEY *pkey;
cd5466
+    EVP_PKEY *pkey, *pkey_new;
cd5466
     RSA *rsa;
cd5466
     VALUE obj;
cd5466
 
cd5466
     GetPKeyRSA(self, pkey);
cd5466
-    /* err check performed by rsa_instance */
cd5466
+    obj = rb_obj_alloc(rb_obj_class(self));
cd5466
+    GetPKey(obj, pkey_new);
cd5466
+
cd5466
     rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey));
cd5466
-    obj = rsa_instance(rb_obj_class(self), rsa);
cd5466
-    if (obj == Qfalse) {
cd5466
-	RSA_free(rsa);
cd5466
-	ossl_raise(eRSAError, NULL);
cd5466
+    if (!rsa)
cd5466
+        ossl_raise(eRSAError, "RSAPublicKey_dup");
cd5466
+    if (!EVP_PKEY_assign_RSA(pkey_new, rsa)) {
cd5466
+        RSA_free(rsa);
cd5466
+        ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
cd5466
     }
cd5466
     return obj;
cd5466
 }
cd5466
-- 
cd5466
2.32.0
cd5466
cd5466
cd5466
From 1e1fedc6c2c9d42bc76b5a24bf0f39c8101f8d53 Mon Sep 17 00:00:00 2001
cd5466
From: Kazuki Yamaguchi <k@rhe.jp>
cd5466
Date: Sat, 18 Mar 2017 17:26:33 +0900
cd5466
Subject: [PATCH 3/5] pkey: have PKey.read parse PEM-encoded DHParameter
cd5466
cd5466
Try PEM_read_bio_Parameters(). Only PEM format is supported at the
cd5466
moment since corresponding d2i_* functions are not provided by OpenSSL.
cd5466
---
cd5466
 ext/openssl/ossl_pkey.c      | 3 +++
cd5466
 test/openssl/test_pkey_dh.rb | 2 ++
cd5466
 test/openssl/utils.rb        | 3 ---
cd5466
 3 files changed, 5 insertions(+), 3 deletions(-)
cd5466
cd5466
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
cd5466
index c6dbf57272..a00d66aada 100644
cd5466
--- a/ext/openssl/ossl_pkey.c
cd5466
+++ b/ext/openssl/ossl_pkey.c
cd5466
@@ -178,6 +178,9 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
cd5466
     OSSL_BIO_reset(bio);
cd5466
     if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
cd5466
 	goto ok;
cd5466
+    OSSL_BIO_reset(bio);
cd5466
+    if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
cd5466
+	goto ok;
cd5466
 
cd5466
     BIO_free(bio);
cd5466
     ossl_raise(ePKeyError, "Could not parse PKey");
cd5466
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
cd5466
index fd2c7a66a9..4a05626a12 100644
cd5466
--- a/test/openssl/test_pkey_dh.rb
cd5466
+++ b/test/openssl/test_pkey_dh.rb
cd5466
@@ -36,6 +36,8 @@ def test_DHparams
cd5466
     EOF
cd5466
     key = OpenSSL::PKey::DH.new(pem)
cd5466
     assert_same_dh dup_public(dh1024), key
cd5466
+    key = OpenSSL::PKey.read(pem)
cd5466
+    assert_same_dh dup_public(dh1024), key
cd5466
 
cd5466
     assert_equal asn1.to_der, dh1024.to_der
cd5466
     assert_equal pem, dh1024.export
cd5466
diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
cd5466
index 3776fbac4e..c1d737b2ab 100644
cd5466
--- a/test/openssl/utils.rb
cd5466
+++ b/test/openssl/utils.rb
cd5466
@@ -42,9 +42,6 @@ module Fixtures
cd5466
 
cd5466
     def pkey(name)
cd5466
       OpenSSL::PKey.read(read_file("pkey", name))
cd5466
-    rescue OpenSSL::PKey::PKeyError
cd5466
-      # TODO: DH parameters can be read by OpenSSL::PKey.read atm
cd5466
-      OpenSSL::PKey::DH.new(read_file("pkey", name))
cd5466
     end
cd5466
 
cd5466
     def read_file(category, name)
cd5466
-- 
cd5466
2.32.0
cd5466
cd5466
cd5466
From 70655b40a980dad36dfb3054d309f6484e2a70b7 Mon Sep 17 00:00:00 2001
cd5466
From: Kazuki Yamaguchi <k@rhe.jp>
cd5466
Date: Tue, 13 Jun 2017 23:39:41 +0900
cd5466
Subject: [PATCH 4/5] pkey: refactor DER/PEM-encoded string parsing code
cd5466
cd5466
Export the flow used by OpenSSL::PKey.read and let the subclasses call
cd5466
it before attempting other formats.
cd5466
---
cd5466
 ext/openssl/ossl_pkey.c     | 57 +++++++++++++++++++++----------------
cd5466
 ext/openssl/ossl_pkey.h     |  1 +
cd5466
 ext/openssl/ossl_pkey_dsa.c | 37 +++++++++++-------------
cd5466
 ext/openssl/ossl_pkey_ec.c  | 29 +++++++------------
cd5466
 ext/openssl/ossl_pkey_rsa.c | 26 ++++++++---------
cd5466
 5 files changed, 73 insertions(+), 77 deletions(-)
cd5466
cd5466
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
cd5466
index a00d66aada..47ddd0f014 100644
cd5466
--- a/ext/openssl/ossl_pkey.c
cd5466
+++ b/ext/openssl/ossl_pkey.c
cd5466
@@ -136,6 +136,35 @@ ossl_pkey_new(EVP_PKEY *pkey)
cd5466
     return obj;
cd5466
 }
cd5466
 
cd5466
+EVP_PKEY *
cd5466
+ossl_pkey_read_generic(BIO *bio, VALUE pass)
cd5466
+{
cd5466
+    void *ppass = (void *)pass;
cd5466
+    EVP_PKEY *pkey;
cd5466
+
cd5466
+    if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
cd5466
+	goto out;
cd5466
+    OSSL_BIO_reset(bio);
cd5466
+    if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
cd5466
+	goto out;
cd5466
+    OSSL_BIO_reset(bio);
cd5466
+    if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
cd5466
+	goto out;
cd5466
+    OSSL_BIO_reset(bio);
cd5466
+    /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
cd5466
+    if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
cd5466
+	goto out;
cd5466
+    OSSL_BIO_reset(bio);
cd5466
+    if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
cd5466
+	goto out;
cd5466
+    OSSL_BIO_reset(bio);
cd5466
+    if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
cd5466
+	goto out;
cd5466
+
cd5466
+  out:
cd5466
+    return pkey;
cd5466
+}
cd5466
+
cd5466
 /*
cd5466
  *  call-seq:
cd5466
  *     OpenSSL::PKey.read(string [, pwd ]) -> PKey
cd5466
@@ -160,33 +189,11 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
cd5466
     VALUE data, pass;
cd5466
 
cd5466
     rb_scan_args(argc, argv, "11", &data, &pass);
cd5466
-    pass = ossl_pem_passwd_value(pass);
cd5466
-
cd5466
     bio = ossl_obj2bio(&data);
cd5466
-    if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
cd5466
-	goto ok;
cd5466
-    OSSL_BIO_reset(bio);
cd5466
-    if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
cd5466
-	goto ok;
cd5466
-    OSSL_BIO_reset(bio);
cd5466
-    if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
cd5466
-	goto ok;
cd5466
-    OSSL_BIO_reset(bio);
cd5466
-    /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
cd5466
-    if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
cd5466
-	goto ok;
cd5466
-    OSSL_BIO_reset(bio);
cd5466
-    if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
cd5466
-	goto ok;
cd5466
-    OSSL_BIO_reset(bio);
cd5466
-    if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
cd5466
-	goto ok;
cd5466
-
cd5466
-    BIO_free(bio);
cd5466
-    ossl_raise(ePKeyError, "Could not parse PKey");
cd5466
-
cd5466
-ok:
cd5466
+    pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
cd5466
     BIO_free(bio);
cd5466
+    if (!pkey)
cd5466
+	ossl_raise(ePKeyError, "Could not parse PKey");
cd5466
     return ossl_pkey_new(pkey);
cd5466
 }
cd5466
 
cd5466
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
cd5466
index e363a261c2..895927e3fb 100644
cd5466
--- a/ext/openssl/ossl_pkey.h
cd5466
+++ b/ext/openssl/ossl_pkey.h
cd5466
@@ -45,6 +45,7 @@ void ossl_generate_cb_stop(void *ptr);
cd5466
 
cd5466
 VALUE ossl_pkey_new(EVP_PKEY *);
cd5466
 void ossl_pkey_check_public_key(const EVP_PKEY *);
cd5466
+EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
cd5466
 EVP_PKEY *GetPKeyPtr(VALUE);
cd5466
 EVP_PKEY *DupPKeyPtr(VALUE);
cd5466
 EVP_PKEY *GetPrivPKeyPtr(VALUE);
cd5466
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
cd5466
index c907f31c19..56f58559ed 100644
cd5466
--- a/ext/openssl/ossl_pkey_dsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_dsa.c
cd5466
@@ -170,37 +170,34 @@ ossl_dsa_s_generate(VALUE klass, VALUE size)
cd5466
 static VALUE
cd5466
 ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
cd5466
 {
cd5466
-    EVP_PKEY *pkey;
cd5466
-    DSA *dsa;
cd5466
+    EVP_PKEY *pkey, *tmp;
cd5466
+    DSA *dsa = NULL;
cd5466
     BIO *in;
cd5466
     VALUE arg, pass;
cd5466
 
cd5466
     GetPKey(self, pkey);
cd5466
-    if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
cd5466
+    rb_scan_args(argc, argv, "02", &arg, &pass);
cd5466
+    if (argc == 0) {
cd5466
         dsa = DSA_new();
cd5466
+        if (!dsa)
cd5466
+            ossl_raise(eDSAError, "DSA_new");
cd5466
     }
cd5466
-    else if (RB_INTEGER_TYPE_P(arg)) {
cd5466
-	if (!(dsa = dsa_generate(NUM2INT(arg)))) {
cd5466
-	    ossl_raise(eDSAError, NULL);
cd5466
-	}
cd5466
+    else if (argc == 1 && RB_INTEGER_TYPE_P(arg)) {
cd5466
+        dsa = dsa_generate(NUM2INT(arg));
cd5466
     }
cd5466
     else {
cd5466
 	pass = ossl_pem_passwd_value(pass);
cd5466
 	arg = ossl_to_der_if_possible(arg);
cd5466
 	in = ossl_obj2bio(&arg;;
cd5466
-	dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
cd5466
-	if (!dsa) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
cd5466
-	}
cd5466
-	if (!dsa) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    dsa = d2i_DSAPrivateKey_bio(in, NULL);
cd5466
-	}
cd5466
-	if (!dsa) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    dsa = d2i_DSA_PUBKEY_bio(in, NULL);
cd5466
-	}
cd5466
+
cd5466
+        tmp = ossl_pkey_read_generic(in, pass);
cd5466
+        if (tmp) {
cd5466
+            if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA)
cd5466
+                rb_raise(eDSAError, "incorrect pkey type: %s",
cd5466
+                         OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
cd5466
+            dsa = EVP_PKEY_get1_DSA(tmp);
cd5466
+            EVP_PKEY_free(tmp);
cd5466
+        }
cd5466
 	if (!dsa) {
cd5466
 	    OSSL_BIO_reset(in);
cd5466
 #define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
cd5466
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
cd5466
index aec9d1e60f..ca8f5c6e4e 100644
cd5466
--- a/ext/openssl/ossl_pkey_ec.c
cd5466
+++ b/ext/openssl/ossl_pkey_ec.c
cd5466
@@ -162,24 +162,17 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
cd5466
     } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
cd5466
 	ec = ec_key_new_from_group(arg);
cd5466
     } else {
cd5466
-	BIO *in;
cd5466
-
cd5466
-	pass = ossl_pem_passwd_value(pass);
cd5466
-	in = ossl_obj2bio(&arg;;
cd5466
-
cd5466
-	ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
cd5466
-	if (!ec) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass);
cd5466
-	}
cd5466
-	if (!ec) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    ec = d2i_ECPrivateKey_bio(in, NULL);
cd5466
-	}
cd5466
-	if (!ec) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    ec = d2i_EC_PUBKEY_bio(in, NULL);
cd5466
-	}
cd5466
+        BIO *in = ossl_obj2bio(&arg;;
cd5466
+        EVP_PKEY *tmp;
cd5466
+        pass = ossl_pem_passwd_value(pass);
cd5466
+        tmp = ossl_pkey_read_generic(in, pass);
cd5466
+        if (tmp) {
cd5466
+            if (EVP_PKEY_base_id(tmp) != EVP_PKEY_EC)
cd5466
+                rb_raise(eECError, "incorrect pkey type: %s",
cd5466
+                         OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
cd5466
+            ec = EVP_PKEY_get1_EC_KEY(tmp);
cd5466
+            EVP_PKEY_free(tmp);
cd5466
+        }
cd5466
 	BIO_free(in);
cd5466
 
cd5466
 	if (!ec) {
cd5466
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
cd5466
index fbdb9c8960..8415121c7d 100644
cd5466
--- a/ext/openssl/ossl_pkey_rsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_rsa.c
cd5466
@@ -179,7 +179,8 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
cd5466
     VALUE arg, pass;
cd5466
 
cd5466
     GetPKey(self, pkey);
cd5466
-    if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
cd5466
+    rb_scan_args(argc, argv, "02", &arg, &pass);
cd5466
+    if (argc == 0) {
cd5466
 	rsa = RSA_new();
cd5466
         if (!rsa)
cd5466
             ossl_raise(eRSAError, "RSA_new");
cd5466
@@ -191,19 +192,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
cd5466
 	pass = ossl_pem_passwd_value(pass);
cd5466
 	arg = ossl_to_der_if_possible(arg);
cd5466
 	in = ossl_obj2bio(&arg;;
cd5466
-	rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
cd5466
-	if (!rsa) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL);
cd5466
-	}
cd5466
-	if (!rsa) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    rsa = d2i_RSAPrivateKey_bio(in, NULL);
cd5466
-	}
cd5466
-	if (!rsa) {
cd5466
-	    OSSL_BIO_reset(in);
cd5466
-	    rsa = d2i_RSA_PUBKEY_bio(in, NULL);
cd5466
-	}
cd5466
+
cd5466
+        tmp = ossl_pkey_read_generic(in, pass);
cd5466
+        if (tmp) {
cd5466
+            if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA)
cd5466
+                rb_raise(eRSAError, "incorrect pkey type: %s",
cd5466
+                         OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
cd5466
+            rsa = EVP_PKEY_get1_RSA(tmp);
cd5466
+            EVP_PKEY_free(tmp);
cd5466
+        }
cd5466
 	if (!rsa) {
cd5466
 	    OSSL_BIO_reset(in);
cd5466
 	    rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
cd5466
@@ -214,6 +211,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
cd5466
 	}
cd5466
 	BIO_free(in);
cd5466
 	if (!rsa) {
cd5466
+            ossl_clear_error();
cd5466
 	    ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
cd5466
 	}
cd5466
     }
cd5466
-- 
cd5466
2.32.0
cd5466
cd5466
cd5466
From eacc680b1efc82935efc945bbe23c9073f17f440 Mon Sep 17 00:00:00 2001
cd5466
From: Kazuki Yamaguchi <k@rhe.jp>
cd5466
Date: Wed, 14 Jun 2017 00:25:43 +0900
cd5466
Subject: [PATCH 5/5] pkey: refactor #export/#to_pem and #to_der
cd5466
cd5466
Add ossl_pkey_export_traditional() and ossl_pkey_export_spki() helper
cd5466
functions, and use them. This reduces code duplication.
cd5466
---
cd5466
 ext/openssl/ossl_pkey.c     | 54 +++++++++++++++++++++--
cd5466
 ext/openssl/ossl_pkey.h     | 14 ++++++
cd5466
 ext/openssl/ossl_pkey_dsa.c | 49 +++------------------
cd5466
 ext/openssl/ossl_pkey_ec.c  | 86 ++++++++-----------------------------
cd5466
 ext/openssl/ossl_pkey_rsa.c | 84 +++++++++++-------------------------
cd5466
 5 files changed, 114 insertions(+), 173 deletions(-)
cd5466
cd5466
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
cd5466
index 47ddd0f014..610a83fd2d 100644
cd5466
--- a/ext/openssl/ossl_pkey.c
cd5466
+++ b/ext/openssl/ossl_pkey.c
cd5466
@@ -341,6 +341,52 @@ ossl_pkey_inspect(VALUE self)
cd5466
                       OBJ_nid2sn(nid));
cd5466
 }
cd5466
 
cd5466
+VALUE
cd5466
+ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
cd5466
+{
cd5466
+    EVP_PKEY *pkey;
cd5466
+    VALUE cipher, pass;
cd5466
+    const EVP_CIPHER *enc = NULL;
cd5466
+    BIO *bio;
cd5466
+
cd5466
+    GetPKey(self, pkey);
cd5466
+    rb_scan_args(argc, argv, "02", &cipher, &pass);
cd5466
+    if (!NIL_P(cipher)) {
cd5466
+	enc = ossl_evp_get_cipherbyname(cipher);
cd5466
+	pass = ossl_pem_passwd_value(pass);
cd5466
+    }
cd5466
+
cd5466
+    bio = BIO_new(BIO_s_mem());
cd5466
+    if (!bio)
cd5466
+	ossl_raise(ePKeyError, "BIO_new");
cd5466
+    if (to_der) {
cd5466
+	if (!i2d_PrivateKey_bio(bio, pkey)) {
cd5466
+	    BIO_free(bio);
cd5466
+	    ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
cd5466
+	}
cd5466
+    }
cd5466
+    else {
cd5466
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
cd5466
+	if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
cd5466
+						  ossl_pem_passwd_cb,
cd5466
+						  (void *)pass)) {
cd5466
+#else
cd5466
+	char pem_str[80];
cd5466
+	const char *aname;
cd5466
+
cd5466
+	EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth);
cd5466
+	snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname);
cd5466
+	if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio,
cd5466
+				pkey, enc, NULL, 0, ossl_pem_passwd_cb,
cd5466
+				(void *)pass)) {
cd5466
+#endif
cd5466
+	    BIO_free(bio);
cd5466
+	    ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
cd5466
+	}
cd5466
+    }
cd5466
+    return ossl_membio2str(bio);
cd5466
+}
cd5466
+
cd5466
 static VALUE
cd5466
 do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
cd5466
 {
cd5466
@@ -410,8 +456,8 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
cd5466
     return do_pkcs8_export(argc, argv, self, 0);
cd5466
 }
cd5466
 
cd5466
-static VALUE
cd5466
-do_spki_export(VALUE self, int to_der)
cd5466
+VALUE
cd5466
+ossl_pkey_export_spki(VALUE self, int to_der)
cd5466
 {
cd5466
     EVP_PKEY *pkey;
cd5466
     BIO *bio;
cd5466
@@ -444,7 +490,7 @@ do_spki_export(VALUE self, int to_der)
cd5466
 static VALUE
cd5466
 ossl_pkey_public_to_der(VALUE self)
cd5466
 {
cd5466
-    return do_spki_export(self, 1);
cd5466
+    return ossl_pkey_export_spki(self, 1);
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
@@ -456,7 +502,7 @@ ossl_pkey_public_to_der(VALUE self)
cd5466
 static VALUE
cd5466
 ossl_pkey_public_to_pem(VALUE self)
cd5466
 {
cd5466
-    return do_spki_export(self, 0);
cd5466
+    return ossl_pkey_export_spki(self, 0);
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
cd5466
index 895927e3fb..7dbaed47bc 100644
cd5466
--- a/ext/openssl/ossl_pkey.h
cd5466
+++ b/ext/openssl/ossl_pkey.h
cd5466
@@ -49,6 +49,20 @@ EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
cd5466
 EVP_PKEY *GetPKeyPtr(VALUE);
cd5466
 EVP_PKEY *DupPKeyPtr(VALUE);
cd5466
 EVP_PKEY *GetPrivPKeyPtr(VALUE);
cd5466
+
cd5466
+/*
cd5466
+ * Serializes _self_ in X.509 SubjectPublicKeyInfo format and returns the
cd5466
+ * resulting String. Sub-classes use this when overriding #to_der.
cd5466
+ */
cd5466
+VALUE ossl_pkey_export_spki(VALUE self, int to_der);
cd5466
+/*
cd5466
+ * Serializes the private key _self_ in the traditional private key format
cd5466
+ * and returns the resulting String. Sub-classes use this when overriding
cd5466
+ * #to_der.
cd5466
+ */
cd5466
+VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self,
cd5466
+				   int to_der);
cd5466
+
cd5466
 void Init_ossl_pkey(void);
cd5466
 
cd5466
 /*
cd5466
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
cd5466
index 56f58559ed..0e68f7f27f 100644
cd5466
--- a/ext/openssl/ossl_pkey_dsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_dsa.c
cd5466
@@ -296,34 +296,12 @@ static VALUE
cd5466
 ossl_dsa_export(int argc, VALUE *argv, VALUE self)
cd5466
 {
cd5466
     DSA *dsa;
cd5466
-    BIO *out;
cd5466
-    const EVP_CIPHER *ciph = NULL;
cd5466
-    VALUE cipher, pass, str;
cd5466
 
cd5466
     GetDSA(self, dsa);
cd5466
-    rb_scan_args(argc, argv, "02", &cipher, &pass);
cd5466
-    if (!NIL_P(cipher)) {
cd5466
-	ciph = ossl_evp_get_cipherbyname(cipher);
cd5466
-	pass = ossl_pem_passwd_value(pass);
cd5466
-    }
cd5466
-    if (!(out = BIO_new(BIO_s_mem()))) {
cd5466
-	ossl_raise(eDSAError, NULL);
cd5466
-    }
cd5466
-    if (DSA_HAS_PRIVATE(dsa)) {
cd5466
-	if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0,
cd5466
-					 ossl_pem_passwd_cb, (void *)pass)){
cd5466
-	    BIO_free(out);
cd5466
-	    ossl_raise(eDSAError, NULL);
cd5466
-	}
cd5466
-    } else {
cd5466
-	if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) {
cd5466
-	    BIO_free(out);
cd5466
-	    ossl_raise(eDSAError, NULL);
cd5466
-	}
cd5466
-    }
cd5466
-    str = ossl_membio2str(out);
cd5466
-
cd5466
-    return str;
cd5466
+    if (DSA_HAS_PRIVATE(dsa))
cd5466
+        return ossl_pkey_export_traditional(argc, argv, self, 0);
cd5466
+    else
cd5466
+        return ossl_pkey_export_spki(self, 0);
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
@@ -337,25 +315,12 @@ static VALUE
cd5466
 ossl_dsa_to_der(VALUE self)
cd5466
 {
cd5466
     DSA *dsa;
cd5466
-    int (*i2d_func)(DSA *, unsigned char **);
cd5466
-    unsigned char *p;
cd5466
-    long len;
cd5466
-    VALUE str;
cd5466
 
cd5466
     GetDSA(self, dsa);
cd5466
-    if(DSA_HAS_PRIVATE(dsa))
cd5466
-	i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey;
cd5466
+    if (DSA_HAS_PRIVATE(dsa))
cd5466
+        return ossl_pkey_export_traditional(0, NULL, self, 1);
cd5466
     else
cd5466
-	i2d_func = i2d_DSA_PUBKEY;
cd5466
-    if((len = i2d_func(dsa, NULL)) <= 0)
cd5466
-	ossl_raise(eDSAError, NULL);
cd5466
-    str = rb_str_new(0, len);
cd5466
-    p = (unsigned char *)RSTRING_PTR(str);
cd5466
-    if(i2d_func(dsa, &p) < 0)
cd5466
-	ossl_raise(eDSAError, NULL);
cd5466
-    ossl_str_adjust(str, p);
cd5466
-
cd5466
-    return str;
cd5466
+        return ossl_pkey_export_spki(self, 1);
cd5466
 }
cd5466
 
cd5466
 
cd5466
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
cd5466
index ca8f5c6e4e..6fe2533e2a 100644
cd5466
--- a/ext/openssl/ossl_pkey_ec.c
cd5466
+++ b/ext/openssl/ossl_pkey_ec.c
cd5466
@@ -141,7 +141,7 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
cd5466
 static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
cd5466
 {
cd5466
     EVP_PKEY *pkey;
cd5466
-    EC_KEY *ec;
cd5466
+    EC_KEY *ec = NULL;
cd5466
     VALUE arg, pass;
cd5466
 
cd5466
     GetPKey(self, pkey);
cd5466
@@ -378,66 +378,6 @@ static VALUE ossl_ec_key_is_private(VALUE self)
cd5466
     return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse;
cd5466
 }
cd5466
 
cd5466
-static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
cd5466
-{
cd5466
-    EC_KEY *ec;
cd5466
-    BIO *out;
cd5466
-    int i = -1;
cd5466
-    int private = 0;
cd5466
-    VALUE str;
cd5466
-    const EVP_CIPHER *cipher = NULL;
cd5466
-
cd5466
-    GetEC(self, ec);
cd5466
-
cd5466
-    if (EC_KEY_get0_public_key(ec) == NULL)
cd5466
-        ossl_raise(eECError, "can't export - no public key set");
cd5466
-
cd5466
-    if (EC_KEY_check_key(ec) != 1)
cd5466
-	ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
cd5466
-
cd5466
-    if (EC_KEY_get0_private_key(ec))
cd5466
-        private = 1;
cd5466
-
cd5466
-    if (!NIL_P(ciph)) {
cd5466
-	cipher = ossl_evp_get_cipherbyname(ciph);
cd5466
-	pass = ossl_pem_passwd_value(pass);
cd5466
-    }
cd5466
-
cd5466
-    if (!(out = BIO_new(BIO_s_mem())))
cd5466
-        ossl_raise(eECError, "BIO_new(BIO_s_mem())");
cd5466
-
cd5466
-    switch(format) {
cd5466
-    case EXPORT_PEM:
cd5466
-    	if (private) {
cd5466
-            i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, ossl_pem_passwd_cb, (void *)pass);
cd5466
-    	} else {
cd5466
-            i = PEM_write_bio_EC_PUBKEY(out, ec);
cd5466
-        }
cd5466
-
cd5466
-    	break;
cd5466
-    case EXPORT_DER:
cd5466
-        if (private) {
cd5466
-            i = i2d_ECPrivateKey_bio(out, ec);
cd5466
-        } else {
cd5466
-            i = i2d_EC_PUBKEY_bio(out, ec);
cd5466
-        }
cd5466
-
cd5466
-    	break;
cd5466
-    default:
cd5466
-        BIO_free(out);
cd5466
-    	ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
cd5466
-    }
cd5466
-
cd5466
-    if (i != 1) {
cd5466
-        BIO_free(out);
cd5466
-        ossl_raise(eECError, "outlen=%d", i);
cd5466
-    }
cd5466
-
cd5466
-    str = ossl_membio2str(out);
cd5466
-
cd5466
-    return str;
cd5466
-}
cd5466
-
cd5466
 /*
cd5466
  *  call-seq:
cd5466
  *     key.export([cipher, pass_phrase]) => String
cd5466
@@ -448,11 +388,16 @@ static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int forma
cd5466
  * instance. Note that encryption will only be effective for a private key,
cd5466
  * public keys will always be encoded in plain text.
cd5466
  */
cd5466
-static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
cd5466
+static VALUE
cd5466
+ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
cd5466
 {
cd5466
-    VALUE cipher, passwd;
cd5466
-    rb_scan_args(argc, argv, "02", &cipher, &passwd);
cd5466
-    return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM);
cd5466
+    EC_KEY *ec;
cd5466
+
cd5466
+    GetEC(self, ec);
cd5466
+    if (EC_KEY_get0_private_key(ec))
cd5466
+        return ossl_pkey_export_traditional(argc, argv, self, 0);
cd5466
+    else
cd5466
+        return ossl_pkey_export_spki(self, 0);
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
@@ -461,9 +406,16 @@ static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
cd5466
  *
cd5466
  *  See the OpenSSL documentation for i2d_ECPrivateKey_bio()
cd5466
  */
cd5466
-static VALUE ossl_ec_key_to_der(VALUE self)
cd5466
+static VALUE
cd5466
+ossl_ec_key_to_der(VALUE self)
cd5466
 {
cd5466
-    return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
cd5466
+    EC_KEY *ec;
cd5466
+
cd5466
+    GetEC(self, ec);
cd5466
+    if (EC_KEY_get0_private_key(ec))
cd5466
+        return ossl_pkey_export_traditional(0, NULL, self, 1);
cd5466
+    else
cd5466
+        return ossl_pkey_export_spki(self, 1);
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
cd5466
index 8415121c7d..3c298a2aea 100644
cd5466
--- a/ext/openssl/ossl_pkey_rsa.c
cd5466
+++ b/ext/openssl/ossl_pkey_rsa.c
cd5466
@@ -173,8 +173,8 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
cd5466
 static VALUE
cd5466
 ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
cd5466
 {
cd5466
-    EVP_PKEY *pkey;
cd5466
-    RSA *rsa;
cd5466
+    EVP_PKEY *pkey, *tmp;
cd5466
+    RSA *rsa = NULL;
cd5466
     BIO *in;
cd5466
     VALUE arg, pass;
cd5466
 
cd5466
@@ -279,6 +279,21 @@ ossl_rsa_is_private(VALUE self)
cd5466
     return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse;
cd5466
 }
cd5466
 
cd5466
+static int
cd5466
+can_export_rsaprivatekey(VALUE self)
cd5466
+{
cd5466
+    RSA *rsa;
cd5466
+    const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
cd5466
+
cd5466
+    GetRSA(self, rsa);
cd5466
+
cd5466
+    RSA_get0_key(rsa, &n, &e, &d);
cd5466
+    RSA_get0_factors(rsa, &p, &q);
cd5466
+    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
cd5466
+
cd5466
+    return n && e && d && p && q && dmp1 && dmq1 && iqmp;
cd5466
+}
cd5466
+
cd5466
 /*
cd5466
  * call-seq:
cd5466
  *   rsa.export([cipher, pass_phrase]) => PEM-format String
cd5466
@@ -292,41 +307,10 @@ ossl_rsa_is_private(VALUE self)
cd5466
 static VALUE
cd5466
 ossl_rsa_export(int argc, VALUE *argv, VALUE self)
cd5466
 {
cd5466
-    RSA *rsa;
cd5466
-    const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
cd5466
-    BIO *out;
cd5466
-    const EVP_CIPHER *ciph = NULL;
cd5466
-    VALUE cipher, pass, str;
cd5466
-
cd5466
-    GetRSA(self, rsa);
cd5466
-
cd5466
-    rb_scan_args(argc, argv, "02", &cipher, &pass);
cd5466
-
cd5466
-    if (!NIL_P(cipher)) {
cd5466
-	ciph = ossl_evp_get_cipherbyname(cipher);
cd5466
-	pass = ossl_pem_passwd_value(pass);
cd5466
-    }
cd5466
-    if (!(out = BIO_new(BIO_s_mem()))) {
cd5466
-	ossl_raise(eRSAError, NULL);
cd5466
-    }
cd5466
-    RSA_get0_key(rsa, &n, &e, &d);
cd5466
-    RSA_get0_factors(rsa, &p, &q);
cd5466
-    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
cd5466
-    if (n && e && d && p && q && dmp1 && dmq1 && iqmp) {
cd5466
-	if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0,
cd5466
-					 ossl_pem_passwd_cb, (void *)pass)) {
cd5466
-	    BIO_free(out);
cd5466
-	    ossl_raise(eRSAError, NULL);
cd5466
-	}
cd5466
-    } else {
cd5466
-	if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) {
cd5466
-	    BIO_free(out);
cd5466
-	    ossl_raise(eRSAError, NULL);
cd5466
-	}
cd5466
-    }
cd5466
-    str = ossl_membio2str(out);
cd5466
-
cd5466
-    return str;
cd5466
+    if (can_export_rsaprivatekey(self))
cd5466
+        return ossl_pkey_export_traditional(argc, argv, self, 0);
cd5466
+    else
cd5466
+        return ossl_pkey_export_spki(self, 0);
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
@@ -338,30 +322,10 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self)
cd5466
 static VALUE
cd5466
 ossl_rsa_to_der(VALUE self)
cd5466
 {
cd5466
-    RSA *rsa;
cd5466
-    const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
cd5466
-    int (*i2d_func)(const RSA *, unsigned char **);
cd5466
-    unsigned char *ptr;
cd5466
-    long len;
cd5466
-    VALUE str;
cd5466
-
cd5466
-    GetRSA(self, rsa);
cd5466
-    RSA_get0_key(rsa, &n, &e, &d);
cd5466
-    RSA_get0_factors(rsa, &p, &q);
cd5466
-    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
cd5466
-    if (n && e && d && p && q && dmp1 && dmq1 && iqmp)
cd5466
-	i2d_func = i2d_RSAPrivateKey;
cd5466
+    if (can_export_rsaprivatekey(self))
cd5466
+        return ossl_pkey_export_traditional(0, NULL, self, 1);
cd5466
     else
cd5466
-	i2d_func = (int (*)(const RSA *, unsigned char **))i2d_RSA_PUBKEY;
cd5466
-    if((len = i2d_func(rsa, NULL)) <= 0)
cd5466
-	ossl_raise(eRSAError, NULL);
cd5466
-    str = rb_str_new(0, len);
cd5466
-    ptr = (unsigned char *)RSTRING_PTR(str);
cd5466
-    if(i2d_func(rsa, &ptr) < 0)
cd5466
-	ossl_raise(eRSAError, NULL);
cd5466
-    ossl_str_adjust(str, ptr);
cd5466
-
cd5466
-    return str;
cd5466
+        return ossl_pkey_export_spki(self, 1);
cd5466
 }
cd5466
 
cd5466
 /*
cd5466
-- 
cd5466
2.32.0
cd5466