[ruby/openssl] 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. https://github.com/ruby/openssl/commit/48a6c391ef
This commit is contained in:
parent
5d1693aac5
commit
3fe8387950
@ -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 @@ module OpenSSL::PKey
|
||||
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 @@ module OpenSSL::PKey
|
||||
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
|
||||
|
@ -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
|
||||
*
|
||||
* puts symm_key1 == symm_key2 # => true
|
||||
* # 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
|
||||
*
|
||||
* 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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -69,29 +69,28 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
|
||||
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
|
||||
|
||||
def test_new_exponent_default
|
||||
assert_equal(65537, OpenSSL::PKey::RSA.new(512).e)
|
||||
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_generate
|
||||
key = OpenSSL::PKey::RSA.generate(512, 17)
|
||||
key = OpenSSL::PKey::RSA.new(512)
|
||||
assert_equal 512, key.n.num_bits
|
||||
assert_equal 17, key.e
|
||||
assert_equal 65537, key.e
|
||||
assert_not_nil key.d
|
||||
|
||||
# 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_s_generate
|
||||
key1 = OpenSSL::PKey::RSA.generate(512)
|
||||
assert_equal 512, key1.n.num_bits
|
||||
assert_equal 65537, key1.e
|
||||
|
||||
# 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user