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