[前][次][番号順一覧][スレッド一覧]

ruby-changes:70360

From: Kazuki <ko1@a...>
Date: Tue, 21 Dec 2021 00:11:17 +0900 (JST)
Subject: [ruby-changes:70360] c1a36ebfda (master): [ruby/openssl] pkey: allocate EVP_PKEY on #initialize

https://git.ruby-lang.org/ruby.git/commit/?id=c1a36ebfda

From c1a36ebfda8ba570173e2844bc584786852e6190 Mon Sep 17 00:00:00 2001
From: Kazuki Yamaguchi <k@r...>
Date: Mon, 12 Apr 2021 18:32:40 +0900
Subject: [ruby/openssl] 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.

https://github.com/ruby/openssl/commit/74f6c61756
---
 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 6fae01db739..9e4f0be5f99 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -55,8 +55,8 @@ pkey_new0(VALUE arg) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey.c#L55
 #endif
       default:           klass = cPKey; break;
     }
-    obj = NewPKey(klass);
-    SetPKey(obj, pkey);
+    obj = rb_obj_alloc(klass);
+    RTYPEDDATA_DATA(obj) = pkey;
     return obj;
 }
 
@@ -512,16 +512,7 @@ DupPKeyPtr(VALUE obj) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey.c#L512
 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 f0476780fb8..ed18bc69276 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -15,19 +15,10 @@ extern VALUE cPKey; https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey.h#L15
 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 ca782bbe59f..04c11b21579 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -72,34 +72,57 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey_dh.c#L72
 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) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey_dh.c#L133
     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) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey_dh.c#L155
 	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 7af00eebecf..15724548467 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -83,50 +83,59 @@ VALUE eDSAError; https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey_dsa.c#L83
 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) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_pkey_dsa.c#L145
     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 (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]