6daba0
From cf070378020088cd7e69b1cb08be68152ab8a078 Mon Sep 17 00:00:00 2001
6daba0
From: Kazuki Yamaguchi <k@rhe.jp>
6daba0
Date: Sun, 17 May 2020 18:25:38 +0900
6daba0
Subject: [PATCH 1/3] pkey: implement #to_text using EVP API
6daba0
6daba0
Use EVP_PKEY_print_private() instead of the low-level API *_print()
6daba0
functions, such as RSA_print().
6daba0
6daba0
EVP_PKEY_print_*() family was added in OpenSSL 1.0.0.
6daba0
6daba0
Note that it falls back to EVP_PKEY_print_public() and
6daba0
EVP_PKEY_print_params() as necessary. This is required for EVP_PKEY_DH
6daba0
type for which _private() fails if the private component is not set in
6daba0
the pkey object.
6daba0
6daba0
Since the new API works in the same way for all key types, we now
6daba0
implement #to_text in the base class OpenSSL::PKey::PKey rather than in
6daba0
each subclass.
6daba0
---
6daba0
 ext/openssl/ossl_pkey.c     | 38 +++++++++++++++++++++++++++++++++++++
6daba0
 ext/openssl/ossl_pkey_dh.c  | 29 ----------------------------
6daba0
 ext/openssl/ossl_pkey_dsa.c | 29 ----------------------------
6daba0
 ext/openssl/ossl_pkey_ec.c  | 27 --------------------------
6daba0
 ext/openssl/ossl_pkey_rsa.c | 31 ------------------------------
6daba0
 test/openssl/test_pkey.rb   |  5 +++++
6daba0
 6 files changed, 43 insertions(+), 116 deletions(-)
6daba0
6daba0
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
6daba0
index f9282b9417..21cd4b2cda 100644
6daba0
--- a/ext/openssl/ossl_pkey.c
6daba0
+++ b/ext/openssl/ossl_pkey.c
6daba0
@@ -539,6 +539,43 @@ ossl_pkey_inspect(VALUE self)
6daba0
                       OBJ_nid2sn(nid));
6daba0
 }
6daba0
 
6daba0
+/*
6daba0
+ * call-seq:
6daba0
+ *    pkey.to_text -> string
6daba0
+ *
6daba0
+ * Dumps key parameters, public key, and private key components contained in
6daba0
+ * the key into a human-readable text.
6daba0
+ *
6daba0
+ * This is intended for debugging purpose.
6daba0
+ *
6daba0
+ * See also the man page EVP_PKEY_print_private(3).
6daba0
+ */
6daba0
+static VALUE
6daba0
+ossl_pkey_to_text(VALUE self)
6daba0
+{
6daba0
+    EVP_PKEY *pkey;
6daba0
+    BIO *bio;
6daba0
+
6daba0
+    GetPKey(self, pkey);
6daba0
+    if (!(bio = BIO_new(BIO_s_mem())))
6daba0
+        ossl_raise(ePKeyError, "BIO_new");
6daba0
+
6daba0
+    if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
6daba0
+        goto out;
6daba0
+    OSSL_BIO_reset(bio);
6daba0
+    if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
6daba0
+        goto out;
6daba0
+    OSSL_BIO_reset(bio);
6daba0
+    if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
6daba0
+        goto out;
6daba0
+
6daba0
+    BIO_free(bio);
6daba0
+    ossl_raise(ePKeyError, "EVP_PKEY_print_params");
6daba0
+
6daba0
+  out:
6daba0
+    return ossl_membio2str(bio);
6daba0
+}
6daba0
+
6daba0
 VALUE
6daba0
 ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
6daba0
 {
6daba0
@@ -1039,6 +1076,7 @@ Init_ossl_pkey(void)
6daba0
     rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
6daba0
     rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
6daba0
     rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
6daba0
+    rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
6daba0
     rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
6daba0
     rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
6daba0
     rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
6daba0
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
6daba0
index 6b477b077c..acd3bf474e 100644
6daba0
--- a/ext/openssl/ossl_pkey_dh.c
6daba0
+++ b/ext/openssl/ossl_pkey_dh.c
6daba0
@@ -266,34 +266,6 @@ ossl_dh_get_params(VALUE self)
6daba0
     return hash;
6daba0
 }
6daba0
 
6daba0
-/*
6daba0
- *  call-seq:
6daba0
- *     dh.to_text -> aString
6daba0
- *
6daba0
- * Prints all parameters of key to buffer
6daba0
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
6daba0
- * Don't use :-)) (I's up to you)
6daba0
- */
6daba0
-static VALUE
6daba0
-ossl_dh_to_text(VALUE self)
6daba0
-{
6daba0
-    DH *dh;
6daba0
-    BIO *out;
6daba0
-    VALUE str;
6daba0
-
6daba0
-    GetDH(self, dh);
6daba0
-    if (!(out = BIO_new(BIO_s_mem()))) {
6daba0
-	ossl_raise(eDHError, NULL);
6daba0
-    }
6daba0
-    if (!DHparams_print(out, dh)) {
6daba0
-	BIO_free(out);
6daba0
-	ossl_raise(eDHError, NULL);
6daba0
-    }
6daba0
-    str = ossl_membio2str(out);
6daba0
-
6daba0
-    return str;
6daba0
-}
6daba0
-
6daba0
 /*
6daba0
  *  call-seq:
6daba0
  *     dh.public_key -> aDH
6daba0
@@ -426,7 +398,6 @@ Init_ossl_dh(void)
6daba0
     rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1);
6daba0
     rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
6daba0
     rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
6daba0
-    rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
6daba0
     rb_define_method(cDH, "export", ossl_dh_export, 0);
6daba0
     rb_define_alias(cDH, "to_pem", "export");
6daba0
     rb_define_alias(cDH, "to_s", "export");
6daba0
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
6daba0
index 1c5a8a737e..f017cceb4a 100644
6daba0
--- a/ext/openssl/ossl_pkey_dsa.c
6daba0
+++ b/ext/openssl/ossl_pkey_dsa.c
6daba0
@@ -264,34 +264,6 @@ ossl_dsa_get_params(VALUE self)
6daba0
     return hash;
6daba0
 }
6daba0
 
6daba0
-/*
6daba0
- *  call-seq:
6daba0
- *    dsa.to_text -> aString
6daba0
- *
6daba0
- * Prints all parameters of key to buffer
6daba0
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
6daba0
- * Don't use :-)) (I's up to you)
6daba0
- */
6daba0
-static VALUE
6daba0
-ossl_dsa_to_text(VALUE self)
6daba0
-{
6daba0
-    DSA *dsa;
6daba0
-    BIO *out;
6daba0
-    VALUE str;
6daba0
-
6daba0
-    GetDSA(self, dsa);
6daba0
-    if (!(out = BIO_new(BIO_s_mem()))) {
6daba0
-	ossl_raise(eDSAError, NULL);
6daba0
-    }
6daba0
-    if (!DSA_print(out, dsa, 0)) { /* offset = 0 */
6daba0
-	BIO_free(out);
6daba0
-	ossl_raise(eDSAError, NULL);
6daba0
-    }
6daba0
-    str = ossl_membio2str(out);
6daba0
-
6daba0
-    return str;
6daba0
-}
6daba0
-
6daba0
 /*
6daba0
  *  call-seq:
6daba0
  *    dsa.public_key -> aDSA
6daba0
@@ -469,7 +441,6 @@ Init_ossl_dsa(void)
6daba0
 
6daba0
     rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
6daba0
     rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
6daba0
-    rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
6daba0
     rb_define_method(cDSA, "export", ossl_dsa_export, -1);
6daba0
     rb_define_alias(cDSA, "to_pem", "export");
6daba0
     rb_define_alias(cDSA, "to_s", "export");
6daba0
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
6daba0
index c2534251c3..ecb8305184 100644
6daba0
--- a/ext/openssl/ossl_pkey_ec.c
6daba0
+++ b/ext/openssl/ossl_pkey_ec.c
6daba0
@@ -417,32 +417,6 @@ ossl_ec_key_to_der(VALUE self)
6daba0
     else
6daba0
         return ossl_pkey_export_spki(self, 1);
6daba0
 }
6daba0
-
6daba0
-/*
6daba0
- *  call-seq:
6daba0
- *     key.to_text   => String
6daba0
- *
6daba0
- *  See the OpenSSL documentation for EC_KEY_print()
6daba0
- */
6daba0
-static VALUE ossl_ec_key_to_text(VALUE self)
6daba0
-{
6daba0
-    EC_KEY *ec;
6daba0
-    BIO *out;
6daba0
-    VALUE str;
6daba0
-
6daba0
-    GetEC(self, ec);
6daba0
-    if (!(out = BIO_new(BIO_s_mem()))) {
6daba0
-	ossl_raise(eECError, "BIO_new(BIO_s_mem())");
6daba0
-    }
6daba0
-    if (!EC_KEY_print(out, ec, 0)) {
6daba0
-	BIO_free(out);
6daba0
-	ossl_raise(eECError, "EC_KEY_print");
6daba0
-    }
6daba0
-    str = ossl_membio2str(out);
6daba0
-
6daba0
-    return str;
6daba0
-}
6daba0
-
6daba0
 /*
6daba0
  *  call-seq:
6daba0
  *     key.generate_key!   => self
6daba0
@@ -1633,7 +1607,6 @@ void Init_ossl_ec(void)
6daba0
     rb_define_method(cEC, "export", ossl_ec_key_export, -1);
6daba0
     rb_define_alias(cEC, "to_pem", "export");
6daba0
     rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
6daba0
-    rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
6daba0
 
6daba0
 
6daba0
     rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
6daba0
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
6daba0
index 43f82cb29e..7a7e66dbda 100644
6daba0
--- a/ext/openssl/ossl_pkey_rsa.c
6daba0
+++ b/ext/openssl/ossl_pkey_rsa.c
6daba0
@@ -587,36 +587,6 @@ ossl_rsa_get_params(VALUE self)
6daba0
     return hash;
6daba0
 }
6daba0
 
6daba0
-/*
6daba0
- * call-seq:
6daba0
- *   rsa.to_text => String
6daba0
- *
6daba0
- * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
6daba0
- *
6daba0
- * Dumps all parameters of a keypair to a String
6daba0
- *
6daba0
- * Don't use :-)) (It's up to you)
6daba0
- */
6daba0
-static VALUE
6daba0
-ossl_rsa_to_text(VALUE self)
6daba0
-{
6daba0
-    RSA *rsa;
6daba0
-    BIO *out;
6daba0
-    VALUE str;
6daba0
-
6daba0
-    GetRSA(self, rsa);
6daba0
-    if (!(out = BIO_new(BIO_s_mem()))) {
6daba0
-	ossl_raise(eRSAError, NULL);
6daba0
-    }
6daba0
-    if (!RSA_print(out, rsa, 0)) { /* offset = 0 */
6daba0
-	BIO_free(out);
6daba0
-	ossl_raise(eRSAError, NULL);
6daba0
-    }
6daba0
-    str = ossl_membio2str(out);
6daba0
-
6daba0
-    return str;
6daba0
-}
6daba0
-
6daba0
 /*
6daba0
  * call-seq:
6daba0
  *    rsa.public_key -> RSA
6daba0
@@ -738,7 +708,6 @@ Init_ossl_rsa(void)
6daba0
 
6daba0
     rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
6daba0
     rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);
6daba0
-    rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0);
6daba0
     rb_define_method(cRSA, "export", ossl_rsa_export, -1);
6daba0
     rb_define_alias(cRSA, "to_pem", "export");
6daba0
     rb_define_alias(cRSA, "to_s", "export");
6daba0
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
6daba0
index 5307fe5b08..3630458b3c 100644
6daba0
--- a/test/openssl/test_pkey.rb
6daba0
+++ b/test/openssl/test_pkey.rb
6daba0
@@ -151,4 +151,9 @@ def test_x25519
6daba0
     assert_equal bob_pem, bob.public_to_pem
6daba0
     assert_equal [shared_secret].pack("H*"), alice.derive(bob)
6daba0
   end
6daba0
+
6daba0
+  def test_to_text
6daba0
+    rsa = Fixtures.pkey("rsa1024")
6daba0
+    assert_include rsa.to_text, "publicExponent"
6daba0
+  end
6daba0
 end
6daba0
-- 
6daba0
2.32.0
6daba0
6daba0
6daba0
From 0c45b22e485bfa62f4d704b08e3704e6444118c4 Mon Sep 17 00:00:00 2001
6daba0
From: Kazuki Yamaguchi <k@rhe.jp>
6daba0
Date: Thu, 15 Apr 2021 19:11:32 +0900
6daba0
Subject: [PATCH 2/3] pkey: implement {DH,DSA,RSA}#public_key in Ruby
6daba0
6daba0
The low-level API that is used to implement #public_key is deprecated
6daba0
in OpenSSL 3.0. It is actually very simple to implement in another way,
6daba0
using existing methods only, in much shorter code. Let's do it.
6daba0
6daba0
While we are at it, the documentation is updated to recommend against
6daba0
using #public_key. Now that OpenSSL::PKey::PKey implements public_to_der
6daba0
method, there is no real use case for #public_key in newly written Ruby
6daba0
programs.
6daba0
---
6daba0
 ext/openssl/lib/openssl/pkey.rb | 55 ++++++++++++++++++++++++++++
6daba0
 ext/openssl/ossl_pkey_dh.c      | 63 +++++++--------------------------
6daba0
 ext/openssl/ossl_pkey_dsa.c     | 42 ----------------------
6daba0
 ext/openssl/ossl_pkey_rsa.c     | 58 +-----------------------------
6daba0
 test/openssl/test_pkey_rsa.rb   | 37 ++++++++++---------
6daba0
 5 files changed, 87 insertions(+), 168 deletions(-)
6daba0
6daba0
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
6daba0
index 53ee52f98b..569559e1ce 100644
6daba0
--- a/ext/openssl/lib/openssl/pkey.rb
6daba0
+++ b/ext/openssl/lib/openssl/pkey.rb
6daba0
@@ -10,6 +10,30 @@ module OpenSSL::PKey
6daba0
   class DH
6daba0
     include OpenSSL::Marshal
6daba0
 
6daba0
+    # :call-seq:
6daba0
+    #    dh.public_key -> dhnew
6daba0
+    #
6daba0
+    # Returns a new DH instance that carries just the \DH parameters.
6daba0
+    #
6daba0
+    # Contrary to the method name, the returned DH object contains only
6daba0
+    # parameters and not the public key.
6daba0
+    #
6daba0
+    # This method is provided for backwards compatibility. In most cases, there
6daba0
+    # is no need to call this method.
6daba0
+    #
6daba0
+    # For the purpose of re-generating the key pair while keeping the
6daba0
+    # parameters, check OpenSSL::PKey.generate_key.
6daba0
+    #
6daba0
+    # Example:
6daba0
+    #   # OpenSSL::PKey::DH.generate by default generates a random key pair
6daba0
+    #   dh1 = OpenSSL::PKey::DH.generate(2048)
6daba0
+    #   p dh1.priv_key #=> #<OpenSSL::BN 1288347...>
6daba0
+    #   dhcopy = dh1.public_key
6daba0
+    #   p dhcopy.priv_key #=> nil
6daba0
+    def public_key
6daba0
+      DH.new(to_der)
6daba0
+    end
6daba0
+
6daba0
     # :call-seq:
6daba0
     #    dh.compute_key(pub_bn) -> string
6daba0
     #
6daba0
@@ -89,6 +113,22 @@ def new(*args, &blk) # :nodoc:
6daba0
   class DSA
6daba0
     include OpenSSL::Marshal
6daba0
 
6daba0
+    # :call-seq:
6daba0
+    #    dsa.public_key -> dsanew
6daba0
+    #
6daba0
+    # Returns a new DSA instance that carries just the \DSA parameters and the
6daba0
+    # public key.
6daba0
+    #
6daba0
+    # This method is provided for backwards compatibility. In most cases, there
6daba0
+    # is no need to call this method.
6daba0
+    #
6daba0
+    # For the purpose of serializing the public key, to PEM or DER encoding of
6daba0
+    # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and
6daba0
+    # PKey#public_to_der.
6daba0
+    def public_key
6daba0
+      OpenSSL::PKey.read(public_to_der)
6daba0
+    end
6daba0
+
6daba0
     class << self
6daba0
       # :call-seq:
6daba0
       #    DSA.generate(size) -> dsa
6daba0
@@ -159,6 +199,21 @@ def to_bn(conversion_form = group.point_conversion_form)
6daba0
   class RSA
6daba0
     include OpenSSL::Marshal
6daba0
 
6daba0
+    # :call-seq:
6daba0
+    #    rsa.public_key -> rsanew
6daba0
+    #
6daba0
+    # Returns a new RSA instance that carries just the public key components.
6daba0
+    #
6daba0
+    # This method is provided for backwards compatibility. In most cases, there
6daba0
+    # is no need to call this method.
6daba0
+    #
6daba0
+    # For the purpose of serializing the public key, to PEM or DER encoding of
6daba0
+    # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and
6daba0
+    # PKey#public_to_der.
6daba0
+    def public_key
6daba0
+      OpenSSL::PKey.read(public_to_der)
6daba0
+    end
6daba0
+
6daba0
     class << self
6daba0
       # :call-seq:
6daba0
       #    RSA.generate(size, exponent = 65537) -> RSA
6daba0
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
6daba0
index acd3bf474e..a512b209d3 100644
6daba0
--- a/ext/openssl/ossl_pkey_dh.c
6daba0
+++ b/ext/openssl/ossl_pkey_dh.c
6daba0
@@ -266,48 +266,6 @@ ossl_dh_get_params(VALUE self)
6daba0
     return hash;
6daba0
 }
6daba0
 
6daba0
-/*
6daba0
- *  call-seq:
6daba0
- *     dh.public_key -> aDH
6daba0
- *
6daba0
- * Returns a new DH instance that carries just the public information, i.e.
6daba0
- * the prime _p_ and the generator _g_, but no public/private key yet. Such
6daba0
- * a pair may be generated using DH#generate_key!. The "public key" needed
6daba0
- * for a key exchange with DH#compute_key is considered as per-session
6daba0
- * information and may be retrieved with DH#pub_key once a key pair has
6daba0
- * been generated.
6daba0
- * If the current instance already contains private information (and thus a
6daba0
- * valid public/private key pair), this information will no longer be present
6daba0
- * in the new instance generated by DH#public_key. This feature is helpful for
6daba0
- * publishing the Diffie-Hellman parameters without leaking any of the private
6daba0
- * per-session information.
6daba0
- *
6daba0
- * === Example
6daba0
- *  dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
6daba0
- *  public_key = dh.public_key # contains only prime and generator
6daba0
- *  parameters = public_key.to_der # it's safe to publish this
6daba0
- */
6daba0
-static VALUE
6daba0
-ossl_dh_to_public_key(VALUE self)
6daba0
-{
6daba0
-    EVP_PKEY *pkey;
6daba0
-    DH *orig_dh, *dh;
6daba0
-    VALUE obj;
6daba0
-
6daba0
-    obj = rb_obj_alloc(rb_obj_class(self));
6daba0
-    GetPKey(obj, pkey);
6daba0
-
6daba0
-    GetDH(self, orig_dh);
6daba0
-    dh = DHparams_dup(orig_dh);
6daba0
-    if (!dh)
6daba0
-        ossl_raise(eDHError, "DHparams_dup");
6daba0
-    if (!EVP_PKEY_assign_DH(pkey, dh)) {
6daba0
-        DH_free(dh);
6daba0
-        ossl_raise(eDHError, "EVP_PKEY_assign_DH");
6daba0
-    }
6daba0
-    return obj;
6daba0
-}
6daba0
-
6daba0
 /*
6daba0
  *  call-seq:
6daba0
  *     dh.params_ok? -> true | false
6daba0
@@ -384,14 +342,20 @@ Init_ossl_dh(void)
6daba0
      *   The per-session private key, an OpenSSL::BN.
6daba0
      *
6daba0
      * === Example of a key exchange
6daba0
-     *  dh1 = OpenSSL::PKey::DH.new(2048)
6daba0
-     *  der = dh1.public_key.to_der #you may send this publicly to the participating party
6daba0
-     *  dh2 = OpenSSL::PKey::DH.new(der)
6daba0
-     *  dh2.generate_key! #generate the per-session key pair
6daba0
-     *  symm_key1 = dh1.compute_key(dh2.pub_key)
6daba0
-     *  symm_key2 = dh2.compute_key(dh1.pub_key)
6daba0
+     *   # you may send the parameters (der) and own public key (pub1) publicly
6daba0
+     *   # to the participating party
6daba0
+     *   dh1 = OpenSSL::PKey::DH.new(2048)
6daba0
+     *   der = dh1.to_der
6daba0
+     *   pub1 = dh1.pub_key
6daba0
+     *
6daba0
+     *   # the other party generates its per-session key pair
6daba0
+     *   dhparams = OpenSSL::PKey::DH.new(der)
6daba0
+     *   dh2 = OpenSSL::PKey.generate_key(dhparams)
6daba0
+     *   pub2 = dh2.pub_key
6daba0
      *
6daba0
-     *  puts symm_key1 == symm_key2 # => true
6daba0
+     *   symm_key1 = dh1.compute_key(pub2)
6daba0
+     *   symm_key2 = dh2.compute_key(pub1)
6daba0
+     *   puts symm_key1 == symm_key2 # => true
6daba0
      */
6daba0
     cDH = rb_define_class_under(mPKey, "DH", cPKey);
6daba0
     rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
6daba0
@@ -402,7 +366,6 @@ Init_ossl_dh(void)
6daba0
     rb_define_alias(cDH, "to_pem", "export");
6daba0
     rb_define_alias(cDH, "to_s", "export");
6daba0
     rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
6daba0
-    rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
6daba0
     rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
6daba0
 
6daba0
     DEF_OSSL_PKEY_BN(cDH, dh, p);
6daba0
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
6daba0
index f017cceb4a..ab9ac781e8 100644
6daba0
--- a/ext/openssl/ossl_pkey_dsa.c
6daba0
+++ b/ext/openssl/ossl_pkey_dsa.c
6daba0
@@ -264,47 +264,6 @@ ossl_dsa_get_params(VALUE self)
6daba0
     return hash;
6daba0
 }
6daba0
 
6daba0
-/*
6daba0
- *  call-seq:
6daba0
- *    dsa.public_key -> aDSA
6daba0
- *
6daba0
- * Returns a new DSA instance that carries just the public key information.
6daba0
- * If the current instance has also private key information, this will no
6daba0
- * longer be present in the new instance. This feature is helpful for
6daba0
- * publishing the public key information without leaking any of the private
6daba0
- * information.
6daba0
- *
6daba0
- * === Example
6daba0
- *  dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information
6daba0
- *  pub_key = dsa.public_key # has only the public part available
6daba0
- *  pub_key_der = pub_key.to_der # it's safe to publish this
6daba0
- *
6daba0
- *
6daba0
- */
6daba0
-static VALUE
6daba0
-ossl_dsa_to_public_key(VALUE self)
6daba0
-{
6daba0
-    EVP_PKEY *pkey, *pkey_new;
6daba0
-    DSA *dsa;
6daba0
-    VALUE obj;
6daba0
-
6daba0
-    GetPKeyDSA(self, pkey);
6daba0
-    obj = rb_obj_alloc(rb_obj_class(self));
6daba0
-    GetPKey(obj, pkey_new);
6daba0
-
6daba0
-#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \
6daba0
-	(i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa))
6daba0
-    dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey));
6daba0
-#undef DSAPublicKey_dup
6daba0
-    if (!dsa)
6daba0
-        ossl_raise(eDSAError, "DSAPublicKey_dup");
6daba0
-    if (!EVP_PKEY_assign_DSA(pkey_new, dsa)) {
6daba0
-        DSA_free(dsa);
6daba0
-        ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
6daba0
-    }
6daba0
-    return obj;
6daba0
-}
6daba0
-
6daba0
 /*
6daba0
  *  call-seq:
6daba0
  *    dsa.syssign(string) -> aString
6daba0
@@ -445,7 +404,6 @@ Init_ossl_dsa(void)
6daba0
     rb_define_alias(cDSA, "to_pem", "export");
6daba0
     rb_define_alias(cDSA, "to_s", "export");
6daba0
     rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
6daba0
-    rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
6daba0
     rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
6daba0
     rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
6daba0
 
6daba0
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
6daba0
index 7a7e66dbda..1c5476cdcd 100644
6daba0
--- a/ext/openssl/ossl_pkey_rsa.c
6daba0
+++ b/ext/openssl/ossl_pkey_rsa.c
6daba0
@@ -390,7 +390,7 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
6daba0
  *   data = "Sign me!"
6daba0
  *   pkey = OpenSSL::PKey::RSA.new(2048)
6daba0
  *   signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256")
6daba0
- *   pub_key = pkey.public_key
6daba0
+ *   pub_key = OpenSSL::PKey.read(pkey.public_to_der)
6daba0
  *   puts pub_key.verify_pss("SHA256", signature, data,
6daba0
  *                           salt_length: :auto, mgf1_hash: "SHA256") # => true
6daba0
  */
6daba0
@@ -587,61 +587,6 @@ ossl_rsa_get_params(VALUE self)
6daba0
     return hash;
6daba0
 }
6daba0
 
6daba0
-/*
6daba0
- * call-seq:
6daba0
- *    rsa.public_key -> RSA
6daba0
- *
6daba0
- * Makes new RSA instance containing the public key from the private key.
6daba0
- */
6daba0
-static VALUE
6daba0
-ossl_rsa_to_public_key(VALUE self)
6daba0
-{
6daba0
-    EVP_PKEY *pkey, *pkey_new;
6daba0
-    RSA *rsa;
6daba0
-    VALUE obj;
6daba0
-
6daba0
-    GetPKeyRSA(self, pkey);
6daba0
-    obj = rb_obj_alloc(rb_obj_class(self));
6daba0
-    GetPKey(obj, pkey_new);
6daba0
-
6daba0
-    rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey));
6daba0
-    if (!rsa)
6daba0
-        ossl_raise(eRSAError, "RSAPublicKey_dup");
6daba0
-    if (!EVP_PKEY_assign_RSA(pkey_new, rsa)) {
6daba0
-        RSA_free(rsa);
6daba0
-        ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
6daba0
-    }
6daba0
-    return obj;
6daba0
-}
6daba0
-
6daba0
-/*
6daba0
- * TODO: Test me
6daba0
-
6daba0
-static VALUE
6daba0
-ossl_rsa_blinding_on(VALUE self)
6daba0
-{
6daba0
-    RSA *rsa;
6daba0
-
6daba0
-    GetRSA(self, rsa);
6daba0
-
6daba0
-    if (RSA_blinding_on(rsa, ossl_bn_ctx) != 1) {
6daba0
-	ossl_raise(eRSAError, NULL);
6daba0
-    }
6daba0
-    return self;
6daba0
-}
6daba0
-
6daba0
-static VALUE
6daba0
-ossl_rsa_blinding_off(VALUE self)
6daba0
-{
6daba0
-    RSA *rsa;
6daba0
-
6daba0
-    GetRSA(self, rsa);
6daba0
-    RSA_blinding_off(rsa);
6daba0
-
6daba0
-    return self;
6daba0
-}
6daba0
- */
6daba0
-
6daba0
 /*
6daba0
  * Document-method: OpenSSL::PKey::RSA#set_key
6daba0
  * call-seq:
6daba0
@@ -712,7 +657,6 @@ Init_ossl_rsa(void)
6daba0
     rb_define_alias(cRSA, "to_pem", "export");
6daba0
     rb_define_alias(cRSA, "to_s", "export");
6daba0
     rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0);
6daba0
-    rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0);
6daba0
     rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1);
6daba0
     rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1);
6daba0
     rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1);
6daba0
diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb
6daba0
index d1e68dbc9f..5f8d04e754 100644
6daba0
--- a/test/openssl/test_pkey_rsa.rb
6daba0
+++ b/test/openssl/test_pkey_rsa.rb
6daba0
@@ -69,29 +69,28 @@ def test_private
6daba0
   end
6daba0
 
6daba0
   def test_new
6daba0
-    key = OpenSSL::PKey::RSA.new 512
6daba0
-    pem  = key.public_key.to_pem
6daba0
-    OpenSSL::PKey::RSA.new pem
6daba0
-    assert_equal([], OpenSSL.errors)
6daba0
-  end
6daba0
+    key = OpenSSL::PKey::RSA.new(512)
6daba0
+    assert_equal 512, key.n.num_bits
6daba0
+    assert_equal 65537, key.e
6daba0
+    assert_not_nil key.d
6daba0
 
6daba0
-  def test_new_exponent_default
6daba0
-    assert_equal(65537, OpenSSL::PKey::RSA.new(512).e)
6daba0
+    # Specify public exponent
6daba0
+    key2 = OpenSSL::PKey::RSA.new(512, 3)
6daba0
+    assert_equal 512, key2.n.num_bits
6daba0
+    assert_equal 3, key2.e
6daba0
+    assert_not_nil key2.d
6daba0
   end
6daba0
 
6daba0
-  def test_new_with_exponent
6daba0
-    1.upto(30) do |idx|
6daba0
-      e = (2 ** idx) + 1
6daba0
-      key = OpenSSL::PKey::RSA.new(512, e)
6daba0
-      assert_equal(e, key.e)
6daba0
-    end
6daba0
-  end
6daba0
+  def test_s_generate
6daba0
+    key1 = OpenSSL::PKey::RSA.generate(512)
6daba0
+    assert_equal 512, key1.n.num_bits
6daba0
+    assert_equal 65537, key1.e
6daba0
 
6daba0
-  def test_generate
6daba0
-    key = OpenSSL::PKey::RSA.generate(512, 17)
6daba0
-    assert_equal 512, key.n.num_bits
6daba0
-    assert_equal 17, key.e
6daba0
-    assert_not_nil key.d
6daba0
+    # Specify public exponent
6daba0
+    key2 = OpenSSL::PKey::RSA.generate(512, 3)
6daba0
+    assert_equal 512, key2.n.num_bits
6daba0
+    assert_equal 3, key2.e
6daba0
+    assert_not_nil key2.d
6daba0
   end
6daba0
 
6daba0
   def test_new_break
6daba0
-- 
6daba0
2.32.0
6daba0
6daba0
6daba0
From 2150af0e55b2a25c24f62006e27e0aec3dc81b57 Mon Sep 17 00:00:00 2001
6daba0
From: Kazuki Yamaguchi <k@rhe.jp>
6daba0
Date: Fri, 10 Jul 2020 14:34:51 +0900
6daba0
Subject: [PATCH 3/3] pkey/dh, pkey/ec: use EVP_PKEY_check() family
6daba0
6daba0
Use EVP_PKEY_param_check() instead of DH_check() if available. Also,
6daba0
use EVP_PKEY_public_check() instead of EC_KEY_check_key().
6daba0
6daba0
EVP_PKEY_*check() is part of the EVP API and is meant to replace those
6daba0
low-level functions. They were added by OpenSSL 1.1.1. It is currently
6daba0
not provided by LibreSSL.
6daba0
---
6daba0
 ext/openssl/extconf.rb       |  3 +++
6daba0
 ext/openssl/ossl_pkey_dh.c   | 27 +++++++++++++++++++++++----
6daba0
 ext/openssl/ossl_pkey_ec.c   | 23 +++++++++++++++++++----
6daba0
 test/openssl/test_pkey_dh.rb | 16 ++++++++++++++++
6daba0
 4 files changed, 61 insertions(+), 8 deletions(-)
6daba0
6daba0
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
6daba0
index b3c6647faf..17d93443fc 100644
6daba0
--- a/ext/openssl/extconf.rb
6daba0
+++ b/ext/openssl/extconf.rb
6daba0
@@ -172,6 +172,9 @@ def find_openssl_library
6daba0
 have_func("EVP_PBE_scrypt")
6daba0
 have_func("SSL_CTX_set_post_handshake_auth")
6daba0
 
6daba0
+# added in 1.1.1
6daba0
+have_func("EVP_PKEY_check")
6daba0
+
6daba0
 Logging::message "=== Checking done. ===\n"
6daba0
 
6daba0
 create_header
6daba0
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
6daba0
index a512b209d3..ca782bbe59 100644
6daba0
--- a/ext/openssl/ossl_pkey_dh.c
6daba0
+++ b/ext/openssl/ossl_pkey_dh.c
6daba0
@@ -273,19 +273,38 @@ ossl_dh_get_params(VALUE self)
6daba0
  * Validates the Diffie-Hellman parameters associated with this instance.
6daba0
  * It checks whether a safe prime and a suitable generator are used. If this
6daba0
  * is not the case, +false+ is returned.
6daba0
+ *
6daba0
+ * See also the man page EVP_PKEY_param_check(3).
6daba0
  */
6daba0
 static VALUE
6daba0
 ossl_dh_check_params(VALUE self)
6daba0
 {
6daba0
+    int ret;
6daba0
+#ifdef HAVE_EVP_PKEY_CHECK
6daba0
+    EVP_PKEY *pkey;
6daba0
+    EVP_PKEY_CTX *pctx;
6daba0
+
6daba0
+    GetPKey(self, pkey);
6daba0
+    pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
6daba0
+    if (!pctx)
6daba0
+        ossl_raise(eDHError, "EVP_PKEY_CTX_new");
6daba0
+    ret = EVP_PKEY_param_check(pctx);
6daba0
+    EVP_PKEY_CTX_free(pctx);
6daba0
+#else
6daba0
     DH *dh;
6daba0
     int codes;
6daba0
 
6daba0
     GetDH(self, dh);
6daba0
-    if (!DH_check(dh, &codes)) {
6daba0
-	return Qfalse;
6daba0
-    }
6daba0
+    ret = DH_check(dh, &codes) == 1 && codes == 0;
6daba0
+#endif
6daba0
 
6daba0
-    return codes == 0 ? Qtrue : Qfalse;
6daba0
+    if (ret == 1)
6daba0
+        return Qtrue;
6daba0
+    else {
6daba0
+        /* DH_check_ex() will put error entry on failure */
6daba0
+        ossl_clear_error();
6daba0
+        return Qfalse;
6daba0
+    }
6daba0
 }
6daba0
 
6daba0
 /*
6daba0
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
6daba0
index ecb8305184..829529d4b9 100644
6daba0
--- a/ext/openssl/ossl_pkey_ec.c
6daba0
+++ b/ext/openssl/ossl_pkey_ec.c
6daba0
@@ -443,20 +443,35 @@ static VALUE ossl_ec_key_generate_key(VALUE self)
6daba0
 }
6daba0
 
6daba0
 /*
6daba0
- *  call-seq:
6daba0
- *     key.check_key   => true
6daba0
+ * call-seq:
6daba0
+ *    key.check_key   => true
6daba0
  *
6daba0
- *  Raises an exception if the key is invalid.
6daba0
+ * Raises an exception if the key is invalid.
6daba0
  *
6daba0
- *  See the OpenSSL documentation for EC_KEY_check_key()
6daba0
+ * See also the man page EVP_PKEY_public_check(3).
6daba0
  */
6daba0
 static VALUE ossl_ec_key_check_key(VALUE self)
6daba0
 {
6daba0
+#ifdef HAVE_EVP_PKEY_CHECK
6daba0
+    EVP_PKEY *pkey;
6daba0
+    EVP_PKEY_CTX *pctx;
6daba0
+    int ret;
6daba0
+
6daba0
+    GetPKey(self, pkey);
6daba0
+    pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
6daba0
+    if (!pctx)
6daba0
+        ossl_raise(eDHError, "EVP_PKEY_CTX_new");
6daba0
+    ret = EVP_PKEY_public_check(pctx);
6daba0
+    EVP_PKEY_CTX_free(pctx);
6daba0
+    if (ret != 1)
6daba0
+        ossl_raise(eECError, "EVP_PKEY_public_check");
6daba0
+#else
6daba0
     EC_KEY *ec;
6daba0
 
6daba0
     GetEC(self, ec);
6daba0
     if (EC_KEY_check_key(ec) != 1)
6daba0
 	ossl_raise(eECError, "EC_KEY_check_key");
6daba0
+#endif
6daba0
 
6daba0
     return Qtrue;
6daba0
 }
6daba0
diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb
6daba0
index 279ce1984c..f80af8f841 100644
6daba0
--- a/test/openssl/test_pkey_dh.rb
6daba0
+++ b/test/openssl/test_pkey_dh.rb
6daba0
@@ -86,6 +86,22 @@ def test_key_exchange
6daba0
     assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key))
6daba0
   end
6daba0
 
6daba0
+  def test_params_ok?
6daba0
+    dh0 = Fixtures.pkey("dh1024")
6daba0
+
6daba0
+    dh1 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([
6daba0
+      OpenSSL::ASN1::Integer(dh0.p),
6daba0
+      OpenSSL::ASN1::Integer(dh0.g)
6daba0
+    ]))
6daba0
+    assert_equal(true, dh1.params_ok?)
6daba0
+
6daba0
+    dh2 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([
6daba0
+      OpenSSL::ASN1::Integer(dh0.p + 1),
6daba0
+      OpenSSL::ASN1::Integer(dh0.g)
6daba0
+    ]))
6daba0
+    assert_equal(false, dh2.params_ok?)
6daba0
+  end
6daba0
+
6daba0
   def test_dup
6daba0
     dh = Fixtures.pkey("dh1024")
6daba0
     dh2 = dh.dup
6daba0
-- 
6daba0
2.32.0
6daba0