aboutsummaryrefslogtreecommitdiffstats
path: root/ext/openssl/ossl_pkey_dh.c
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2021-04-12 18:32:40 +0900
committerKazuki Yamaguchi <k@rhe.jp>2021-12-12 18:20:36 +0900
commit74f6c6175688502a5bf27ae35367616858630c0f (patch)
tree4503d29c84957e632f2aa0b76fc103905eb3f032 /ext/openssl/ossl_pkey_dh.c
parent316cb2a41f154e4663d7e7fead60cfc0bfa86af9 (diff)
downloadruby-openssl-74f6c6175688502a5bf27ae35367616858630c0f.tar.gz
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.
Diffstat (limited to 'ext/openssl/ossl_pkey_dh.c')
-rw-r--r--ext/openssl/ossl_pkey_dh.c71
1 files changed, 50 insertions, 21 deletions
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;
}