Skip to content

Commit

Permalink
pkey: allocate EVP_PKEY on #initialize
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rhenium committed Dec 12, 2021
1 parent 316cb2a commit 74f6c61
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 163 deletions.
15 changes: 3 additions & 12 deletions ext/openssl/ossl_pkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,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;
}

Expand Down Expand Up @@ -472,16 +472,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);
}

/*
Expand Down
15 changes: 3 additions & 12 deletions ext/openssl/ossl_pkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)) { \
Expand Down
71 changes: 50 additions & 21 deletions ext/openssl/ossl_pkey_dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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) {
Expand All @@ -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;
}

Expand Down
93 changes: 55 additions & 38 deletions ext/openssl/ossl_pkey_dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}
Expand Down

0 comments on commit 74f6c61

Please sign in to comment.