From 316cb2a41f154e4663d7e7fead60cfc0bfa86af9 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Mon, 12 Apr 2021 13:55:10 +0900 Subject: [PATCH 1/2] pkey: do not check NULL argument in ossl_pkey_new() Passing NULL to ossl_pkey_new() makes no sense in the first place, and in fact it is ensured not to be NULL in all cases. --- ext/openssl/ossl_pkey.c | 6 +----- ext/openssl/ossl_pkey.h | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index f9f5162e..820e4a2c 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -38,12 +38,8 @@ static VALUE pkey_new0(EVP_PKEY *pkey) { 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 diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index 4beede22..f0476780 100644 --- a/ext/openssl/ossl_pkey.h +++ b/ext/openssl/ossl_pkey.h @@ -35,6 +35,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); From 74f6c6175688502a5bf27ae35367616858630c0f Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Mon, 12 Apr 2021 18:32:40 +0900 Subject: [PATCH 2/2] 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. --- ext/openssl/ossl_pkey.c | 15 ++---- ext/openssl/ossl_pkey.h | 15 ++---- ext/openssl/ossl_pkey_dh.c | 71 +++++++++++++++++++-------- ext/openssl/ossl_pkey_dsa.c | 93 ++++++++++++++++++++--------------- ext/openssl/ossl_pkey_ec.c | 91 +++++++++++++++++++---------------- ext/openssl/ossl_pkey_rsa.c | 96 ++++++++++++++++++++++--------------- 6 files changed, 218 insertions(+), 163 deletions(-) diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 820e4a2c..ea75d63f 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -54,8 +54,8 @@ pkey_new0(EVP_PKEY *pkey) #endif default: klass = cPKey; break; } - obj = NewPKey(klass); - SetPKey(obj, pkey); + obj = rb_obj_alloc(klass); + RTYPEDDATA_DATA(obj) = pkey; return obj; } @@ -511,16 +511,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); } /* diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index f0476780..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)) { \ diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index ca782bbe..04c11b21 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -72,34 +72,57 @@ 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; } @@ -110,15 +133,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,6 +155,13 @@ 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; } diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index 7af00eeb..15724548 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -83,50 +83,59 @@ 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; } @@ -136,16 +145,24 @@ 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; } diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index db80d112..71e63969 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -114,13 +114,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"); @@ -141,51 +144,54 @@ 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; } @@ -195,18 +201,21 @@ 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; } diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 8ebd3ec5..b8dbc0e1 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -76,51 +76,62 @@ 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; } @@ -130,16 +141,23 @@ 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; }