aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2021-12-12 18:49:02 +0900
committerGitHub <noreply@github.com>2021-12-12 18:49:02 +0900
commit88b7577b26f3d810335fc345f9ddca9af1102f4e (patch)
treeea85a28cf9f153247fb3b96412db697d92fa2a75
parent1cd06675f52f47d31c4ef39160983a2ce4e9b62b (diff)
parent66cd8cbaaf85604a13fd68bd9cd280a2881044ad (diff)
downloadruby-openssl-88b7577b26f3d810335fc345f9ddca9af1102f4e.tar.gz
Merge pull request #478 from rhenium/ky/pkey-base-dup
pkey: allocate EVP_PKEY on #initialize
-rw-r--r--ext/openssl/extconf.rb1
-rw-r--r--ext/openssl/ossl_pkey.c46
-rw-r--r--ext/openssl/ossl_pkey.h16
-rw-r--r--ext/openssl/ossl_pkey_dh.c75
-rw-r--r--ext/openssl/ossl_pkey_dsa.c97
-rw-r--r--ext/openssl/ossl_pkey_ec.c96
-rw-r--r--ext/openssl/ossl_pkey_rsa.c100
7 files changed, 262 insertions, 169 deletions
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 1d38b569..fedcb930 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -179,6 +179,7 @@ have_func("BN_check_prime")
have_func("EVP_MD_CTX_get0_md")
have_func("EVP_MD_CTX_get_pkey_ctx")
have_func("EVP_PKEY_eq")
+have_func("EVP_PKEY_dup")
Logging::message "=== Checking done. ===\n"
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index b08168a5..7030be3c 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -39,12 +39,8 @@ pkey_new0(VALUE arg)
{
EVP_PKEY *pkey = (EVP_PKEY *)arg;
VALUE klass, obj;
- int type;
- if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
- ossl_raise(rb_eRuntimeError, "pkey is empty");
-
- switch (type) {
+ switch (EVP_PKEY_base_id(pkey)) {
#if !defined(OPENSSL_NO_RSA)
case EVP_PKEY_RSA: klass = cRSA; break;
#endif
@@ -59,8 +55,8 @@ pkey_new0(VALUE arg)
#endif
default: klass = cPKey; break;
}
- obj = NewPKey(klass);
- SetPKey(obj, pkey);
+ obj = rb_obj_alloc(klass);
+ RTYPEDDATA_DATA(obj) = pkey;
return obj;
}
@@ -516,16 +512,7 @@ DupPKeyPtr(VALUE obj)
static VALUE
ossl_pkey_alloc(VALUE klass)
{
- EVP_PKEY *pkey;
- VALUE obj;
-
- obj = NewPKey(klass);
- if (!(pkey = EVP_PKEY_new())) {
- ossl_raise(ePKeyError, NULL);
- }
- SetPKey(obj, pkey);
-
- return obj;
+ return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
}
/*
@@ -544,6 +531,26 @@ ossl_pkey_initialize(VALUE self)
return self;
}
+#ifdef HAVE_EVP_PKEY_DUP
+static VALUE
+ossl_pkey_initialize_copy(VALUE self, VALUE other)
+{
+ EVP_PKEY *pkey, *pkey_other;
+
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
+ if (pkey_other) {
+ pkey = EVP_PKEY_dup(pkey_other);
+ if (!pkey)
+ ossl_raise(ePKeyError, "EVP_PKEY_dup");
+ RTYPEDDATA_DATA(self) = pkey;
+ }
+ return self;
+}
+#endif
+
/*
* call-seq:
* pkey.oid -> string
@@ -1521,6 +1528,11 @@ Init_ossl_pkey(void)
rb_define_alloc_func(cPKey, ossl_pkey_alloc);
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
+#ifdef HAVE_EVP_PKEY_DUP
+ rb_define_method(cPKey, "initialize_copy", ossl_pkey_initialize_copy, 1);
+#else
+ rb_undef_method(cPKey, "initialize_copy");
+#endif
rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 4beede22..ed18bc69 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -15,19 +15,10 @@ extern VALUE cPKey;
extern VALUE ePKeyError;
extern const rb_data_type_t ossl_evp_pkey_type;
-#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue)
-#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse)
-#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue)
+/* For ENGINE */
+#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern("private"), Qtrue)
+#define OSSL_PKEY_IS_PRIVATE(obj) (rb_attr_get((obj), rb_intern("private")) == Qtrue)
-#define NewPKey(klass) \
- TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, 0)
-#define SetPKey(obj, pkey) do { \
- if (!(pkey)) { \
- rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \
- } \
- RTYPEDDATA_DATA(obj) = (pkey); \
- OSSL_PKEY_SET_PUBLIC(obj); \
-} while (0)
#define GetPKey(obj, pkey) do {\
TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
if (!(pkey)) { \
@@ -35,6 +26,7 @@ extern const rb_data_type_t ossl_evp_pkey_type;
} \
} while (0)
+/* Takes ownership of the EVP_PKEY */
VALUE ossl_pkey_new(EVP_PKEY *);
void ossl_pkey_check_public_key(const EVP_PKEY *);
EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index ca782bbe..d6f32c62 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -72,37 +72,61 @@ static VALUE
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
+ int type;
DH *dh;
- BIO *in;
+ BIO *in = NULL;
VALUE arg;
- GetPKey(self, pkey);
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
+
/* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
dh = DH_new();
if (!dh)
ossl_raise(eDHError, "DH_new");
+ goto legacy;
}
- else {
- arg = ossl_to_der_if_possible(arg);
- in = ossl_obj2bio(&arg);
- dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
- if (!dh){
- OSSL_BIO_reset(in);
- dh = d2i_DHparams_bio(in, NULL);
- }
- BIO_free(in);
- if (!dh) {
- ossl_raise(eDHError, NULL);
- }
+
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
+
+ /*
+ * On OpenSSL <= 1.1.1 and current versions of LibreSSL, the generic
+ * routine does not support DER-encoded parameters
+ */
+ dh = d2i_DHparams_bio(in, NULL);
+ if (dh)
+ goto legacy;
+ OSSL_BIO_reset(in);
+
+ pkey = ossl_pkey_read_generic(in, Qnil);
+ BIO_free(in);
+ if (!pkey)
+ ossl_raise(eDHError, "could not parse pkey");
+
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_DH) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
- if (!EVP_PKEY_assign_DH(pkey, dh)) {
- DH_free(dh);
- ossl_raise(eDHError, NULL);
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+
+ legacy:
+ BIO_free(in);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
+ EVP_PKEY_free(pkey);
+ DH_free(dh);
+ ossl_raise(eDHError, "EVP_PKEY_assign_DH");
}
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#ifndef HAVE_EVP_PKEY_DUP
static VALUE
ossl_dh_initialize_copy(VALUE self, VALUE other)
{
@@ -110,15 +134,14 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
DH *dh, *dh_other;
const BIGNUM *pub, *priv;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eDHError, "DH already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetDH(other, dh_other);
dh = DHparams_dup(dh_other);
if (!dh)
ossl_raise(eDHError, "DHparams_dup");
- EVP_PKEY_assign_DH(pkey, dh);
DH_get0_key(dh_other, &pub, &priv);
if (pub) {
@@ -133,8 +156,16 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
DH_set0_key(dh, pub2, priv2);
}
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
+ EVP_PKEY_free(pkey);
+ DH_free(dh);
+ ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#endif
/*
* call-seq:
@@ -378,7 +409,9 @@ Init_ossl_dh(void)
*/
cDH = rb_define_class_under(mPKey, "DH", cPKey);
rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1);
+#endif
rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
rb_define_method(cDH, "export", ossl_dh_export, 0);
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 7af00eeb..25404aa7 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -83,72 +83,91 @@ VALUE eDSAError;
static VALUE
ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
{
- EVP_PKEY *pkey, *tmp;
- DSA *dsa = NULL;
- BIO *in;
+ EVP_PKEY *pkey;
+ DSA *dsa;
+ BIO *in = NULL;
VALUE arg, pass;
+ int type;
+
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
- GetPKey(self, pkey);
/* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
dsa = DSA_new();
if (!dsa)
ossl_raise(eDSAError, "DSA_new");
+ goto legacy;
}
- else {
- pass = ossl_pem_passwd_value(pass);
- arg = ossl_to_der_if_possible(arg);
- in = ossl_obj2bio(&arg);
-
- tmp = ossl_pkey_read_generic(in, pass);
- if (tmp) {
- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA)
- rb_raise(eDSAError, "incorrect pkey type: %s",
- OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
- dsa = EVP_PKEY_get1_DSA(tmp);
- EVP_PKEY_free(tmp);
- }
- if (!dsa) {
- OSSL_BIO_reset(in);
-#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
- (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u))
- dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
-#undef PEM_read_bio_DSAPublicKey
- }
- BIO_free(in);
- if (!dsa) {
- ossl_clear_error();
- ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
- }
- }
- if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
- DSA_free(dsa);
- ossl_raise(eDSAError, NULL);
+
+ pass = ossl_pem_passwd_value(pass);
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
+
+ /* DER-encoded DSAPublicKey format isn't supported by the generic routine */
+ dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey,
+ PEM_STRING_DSA_PUBLIC,
+ in, NULL, NULL, NULL);
+ if (dsa)
+ goto legacy;
+ OSSL_BIO_reset(in);
+
+ pkey = ossl_pkey_read_generic(in, pass);
+ BIO_free(in);
+ if (!pkey)
+ ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
+
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_DSA) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+ legacy:
+ BIO_free(in);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
+ EVP_PKEY_free(pkey);
+ DSA_free(dsa);
+ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#ifndef HAVE_EVP_PKEY_DUP
static VALUE
ossl_dsa_initialize_copy(VALUE self, VALUE other)
{
EVP_PKEY *pkey;
DSA *dsa, *dsa_new;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eDSAError, "DSA already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetDSA(other, dsa);
- dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa);
+ dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey,
+ (d2i_of_void *)d2i_DSAPrivateKey,
+ (char *)dsa);
if (!dsa_new)
ossl_raise(eDSAError, "ASN1_dup");
- EVP_PKEY_assign_DSA(pkey, dsa_new);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
+ EVP_PKEY_free(pkey);
+ DSA_free(dsa_new);
+ ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#endif
/*
* call-seq:
@@ -310,7 +329,9 @@ Init_ossl_dsa(void)
cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1);
+#endif
rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index db80d112..3b4930f3 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -109,13 +109,16 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
VALUE obj;
obj = rb_obj_alloc(klass);
- GetPKey(obj, pkey);
ec = ec_key_new_from_group(arg);
- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+ EVP_PKEY_free(pkey);
EC_KEY_free(ec);
ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
}
+ RTYPEDDATA_DATA(obj) = pkey;
+
if (!EC_KEY_generate_key(ec))
ossl_raise(eECError, "EC_KEY_generate_key");
@@ -136,75 +139,83 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- EC_KEY *ec = NULL;
+ EC_KEY *ec;
+ BIO *in;
VALUE arg, pass;
+ int type;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eECError, "EC_KEY already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
rb_scan_args(argc, argv, "02", &arg, &pass);
-
if (NIL_P(arg)) {
if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, NULL);
- } else if (rb_obj_is_kind_of(arg, cEC)) {
- EC_KEY *other_ec = NULL;
+ ossl_raise(eECError, "EC_KEY_new");
+ goto legacy;
+ }
+ else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
+ ec = ec_key_new_from_group(arg);
+ goto legacy;
+ }
- GetEC(arg, other_ec);
- if (!(ec = EC_KEY_dup(other_ec)))
- ossl_raise(eECError, NULL);
- } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
- ec = ec_key_new_from_group(arg);
- } else {
- BIO *in = ossl_obj2bio(&arg);
- EVP_PKEY *tmp;
- pass = ossl_pem_passwd_value(pass);
- tmp = ossl_pkey_read_generic(in, pass);
- if (tmp) {
- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_EC)
- rb_raise(eECError, "incorrect pkey type: %s",
- OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
- ec = EVP_PKEY_get1_EC_KEY(tmp);
- EVP_PKEY_free(tmp);
- }
- BIO_free(in);
+ pass = ossl_pem_passwd_value(pass);
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
- if (!ec) {
- ossl_clear_error();
- ec = ec_key_new_from_group(arg);
- }
+ pkey = ossl_pkey_read_generic(in, pass);
+ BIO_free(in);
+ if (!pkey) {
+ ossl_clear_error();
+ ec = ec_key_new_from_group(arg);
+ goto legacy;
}
- if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
- EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_EC) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+ legacy:
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(ec);
+ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#ifndef HAVE_EVP_PKEY_DUP
static VALUE
ossl_ec_key_initialize_copy(VALUE self, VALUE other)
{
EVP_PKEY *pkey;
EC_KEY *ec, *ec_new;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eECError, "EC already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetEC(other, ec);
ec_new = EC_KEY_dup(ec);
if (!ec_new)
ossl_raise(eECError, "EC_KEY_dup");
- if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) {
- EC_KEY_free(ec_new);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {
+ EC_KEY_free(ec_new);
+ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
}
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#endif
/*
* call-seq:
@@ -1514,8 +1525,9 @@ void Init_ossl_ec(void)
rb_define_singleton_method(cEC, "generate", ossl_ec_key_s_generate, 1);
rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
rb_define_method(cEC, "initialize_copy", ossl_ec_key_initialize_copy, 1);
-/* copy/dup/cmp */
+#endif
rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 8ebd3ec5..4d66010f 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -76,73 +76,93 @@ VALUE eRSAError;
static VALUE
ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
{
- EVP_PKEY *pkey, *tmp;
- RSA *rsa = NULL;
- BIO *in;
+ EVP_PKEY *pkey;
+ RSA *rsa;
+ BIO *in = NULL;
VALUE arg, pass;
+ int type;
+
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
- GetPKey(self, pkey);
/* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
rsa = RSA_new();
if (!rsa)
ossl_raise(eRSAError, "RSA_new");
+ goto legacy;
}
- else {
- pass = ossl_pem_passwd_value(pass);
- arg = ossl_to_der_if_possible(arg);
- in = ossl_obj2bio(&arg);
-
- tmp = ossl_pkey_read_generic(in, pass);
- if (tmp) {
- if (EVP_PKEY_base_id(tmp) != EVP_PKEY_RSA)
- rb_raise(eRSAError, "incorrect pkey type: %s",
- OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
- rsa = EVP_PKEY_get1_RSA(tmp);
- EVP_PKEY_free(tmp);
- }
- if (!rsa) {
- OSSL_BIO_reset(in);
- rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
- }
- if (!rsa) {
- OSSL_BIO_reset(in);
- rsa = d2i_RSAPublicKey_bio(in, NULL);
- }
- BIO_free(in);
- if (!rsa) {
- ossl_clear_error();
- ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
- }
- }
- if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
- RSA_free(rsa);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+
+ pass = ossl_pem_passwd_value(pass);
+ arg = ossl_to_der_if_possible(arg);
+ in = ossl_obj2bio(&arg);
+
+ /* First try RSAPublicKey format */
+ rsa = d2i_RSAPublicKey_bio(in, NULL);
+ if (rsa)
+ goto legacy;
+ OSSL_BIO_reset(in);
+ rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
+ if (rsa)
+ goto legacy;
+ OSSL_BIO_reset(in);
+
+ /* Use the generic routine */
+ pkey = ossl_pkey_read_generic(in, pass);
+ BIO_free(in);
+ if (!pkey)
+ ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
+
+ type = EVP_PKEY_base_id(pkey);
+ if (type != EVP_PKEY_RSA) {
+ EVP_PKEY_free(pkey);
+ rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
+ RTYPEDDATA_DATA(self) = pkey;
+ return self;
+ legacy:
+ BIO_free(in);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
+ EVP_PKEY_free(pkey);
+ RSA_free(rsa);
+ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#ifndef HAVE_EVP_PKEY_DUP
static VALUE
ossl_rsa_initialize_copy(VALUE self, VALUE other)
{
EVP_PKEY *pkey;
RSA *rsa, *rsa_new;
- GetPKey(self, pkey);
- if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
- ossl_raise(eRSAError, "RSA already initialized");
+ TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
+ if (pkey)
+ rb_raise(rb_eTypeError, "pkey already initialized");
GetRSA(other, rsa);
- rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa);
+ rsa_new = (RSA *)ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey,
+ (d2i_of_void *)d2i_RSAPrivateKey,
+ (char *)rsa);
if (!rsa_new)
ossl_raise(eRSAError, "ASN1_dup");
- EVP_PKEY_assign_RSA(pkey, rsa_new);
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) {
+ RSA_free(rsa_new);
+ ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ }
+ RTYPEDDATA_DATA(self) = pkey;
return self;
}
+#endif
/*
* call-seq:
@@ -517,7 +537,9 @@ Init_ossl_rsa(void)
cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1);
+#endif
rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);