Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Openssl3 #864

Merged
merged 9 commits into from Apr 29, 2022
4 changes: 4 additions & 0 deletions Rakefile
Expand Up @@ -95,6 +95,10 @@ Rake::TestTask.new do |t|
t.test_files = test_files
end

# We need to enable the OpenSSL 3.0 legacy providers for our test suite
require 'openssl'
ENV['OPENSSL_CONF'] = 'test/openssl3.conf' if OpenSSL::OPENSSL_LIBRARY_VERSION.start_with? "OpenSSL 3"

desc "Run tests of Net::SSH:Test"
Rake::TestTask.new do |t|
t.name = "test_test"
Expand Down
63 changes: 36 additions & 27 deletions lib/net/ssh/buffer.rb
Expand Up @@ -284,11 +284,7 @@ def read_private_keyblob(type)
end
key
when /^ecdsa\-sha2\-(\w*)$/
key = OpenSSL::PKey::EC.read_keyblob($1, self)
key.private_key = read_bignum
_key_comment = read_string

key
OpenSSL::PKey::EC.read_keyblob($1, self)
else
raise Exception, "Cannot decode private key of type #{type}"
end
Expand All @@ -301,29 +297,42 @@ def read_keyblob(type)
when /^(.*)-cert-v01@openssh\.com$/
key = Net::SSH::Authentication::Certificate.read_certblob(self, $1)
when /^ssh-dss$/
key = OpenSSL::PKey::DSA.new
if key.respond_to?(:set_pqg)
key.set_pqg(read_bignum, read_bignum, read_bignum)
else
key.p = read_bignum
key.q = read_bignum
key.g = read_bignum
end
if key.respond_to?(:set_key)
key.set_key(read_bignum, nil)
else
key.pub_key = read_bignum
end
p = read_bignum
q = read_bignum
g = read_bignum
pub_key = read_bignum

asn1 = OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::ObjectId.new('DSA'),
OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Integer.new(p),
OpenSSL::ASN1::Integer.new(q),
OpenSSL::ASN1::Integer.new(g)
]
)
]
),
OpenSSL::ASN1::BitString.new(OpenSSL::ASN1::Integer.new(pub_key).to_der)
]
)

key = OpenSSL::PKey::DSA.new(asn1.to_der)
when /^ssh-rsa$/
key = OpenSSL::PKey::RSA.new
if key.respond_to?(:set_key)
e = read_bignum
n = read_bignum
key.set_key(n, e, nil)
else
key.e = read_bignum
key.n = read_bignum
end
e = read_bignum
n = read_bignum

asn1 = OpenSSL::ASN1::Sequence(
[
OpenSSL::ASN1::Integer(n),
OpenSSL::ASN1::Integer(e)
]
)

key = OpenSSL::PKey::RSA.new(asn1.to_der)
when /^ssh-ed25519$/
Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("unsupported key type `#{type}'")
key = Net::SSH::Authentication::ED25519::PubKey.read_keyblob(self)
Expand Down
34 changes: 17 additions & 17 deletions lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
Expand Up @@ -60,25 +60,25 @@ def build_signature_buffer(result)
# Generate a DH key with a private key consisting of the given
# number of bytes.
def generate_key # :nodoc:
dh = OpenSSL::PKey::DH.new

if dh.respond_to?(:set_pqg)
p, g = get_parameters
dh.set_pqg(p, nil, g)
p, g = get_parameters

asn1 = OpenSSL::ASN1::Sequence(
[
OpenSSL::ASN1::Integer(p),
OpenSSL::ASN1::Integer(g)
]
)

dh_params = OpenSSL::PKey::DH.new(asn1.to_der)
# XXX No private key size check! In theory the latter call should work but fails on OpenSSL 3.0 as
# dh_paramgen_subprime_len is now reserved for DHX algorithm
# key = OpenSSL::PKey.generate_key(dh_params, "dh_paramgen_subprime_len" => data[:need_bytes]/8)
if OpenSSL::PKey.respond_to?(:generate_key)
OpenSSL::PKey.generate_key(dh_params)
else
dh.p, dh.g = get_parameters
end

dh.generate_key!
until dh.valid? && dh.priv_key.num_bytes == data[:need_bytes]
if dh.respond_to?(:set_key)
dh.set_key(nil, OpenSSL::BN.rand(data[:need_bytes] * 8))
else
dh.priv_key = OpenSSL::BN.rand(data[:need_bytes] * 8)
end
dh.generate_key!
dh_params.generate_key!
dh_params
end
dh
end

# Send the KEXDH_INIT message, and expect the KEXDH_REPLY. Return the
Expand Down
2 changes: 1 addition & 1 deletion lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
Expand Up @@ -18,7 +18,7 @@ def curve_name
private

def generate_key # :nodoc:
OpenSSL::PKey::EC.new(curve_name).generate_key
OpenSSL::PKey::EC.generate(curve_name)
end

# compute shared secret from server's public key and client's private key
Expand Down
18 changes: 15 additions & 3 deletions lib/net/ssh/transport/openssl.rb
Expand Up @@ -159,10 +159,22 @@ def self.read_keyblob(curve_name_in_type, buffer)

public_key_oct = buffer.read_string
begin
key = OpenSSL::PKey::EC.new(OpenSSL::PKey::EC::CurveNameAlias[curve_name_in_key])
group = key.group
curvename = OpenSSL::PKey::EC::CurveNameAlias[curve_name_in_key]
group = OpenSSL::PKey::EC::Group.new(curvename)
point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_oct, 2))
key.public_key = point
asn1 = OpenSSL::ASN1::Sequence(
[
OpenSSL::ASN1::Sequence(
[
OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
OpenSSL::ASN1::ObjectId(curvename)
]
),
OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
]
)

key = OpenSSL::PKey::EC.new(asn1.to_der)

return key
rescue OpenSSL::PKey::ECError
Expand Down
4 changes: 2 additions & 2 deletions test/authentication/test_agent.rb
Expand Up @@ -292,7 +292,7 @@ def test_add_dsa_cert_identity
end

def test_add_ecdsa_identity
ecdsa = OpenSSL::PKey::EC.new("prime256v1").generate_key
ecdsa = OpenSSL::PKey::EC.generate("prime256v1")
socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ecdsa-sha2-nistp256"
Expand All @@ -309,7 +309,7 @@ def test_add_ecdsa_identity
end

def test_add_ecdsa_cert_identity
cert = make_cert(OpenSSL::PKey::EC.new("prime256v1").generate_key)
cert = make_cert(OpenSSL::PKey::EC.generate("prime256v1"))
socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ecdsa-sha2-nistp256-cert-v01@openssh.com"
Expand Down
6 changes: 3 additions & 3 deletions test/authentication/test_key_manager.rb
Expand Up @@ -330,15 +330,15 @@ def dsa
end

def ecdsa_sha2_nistp256
@ecdsa_sha2_nistp256 ||= OpenSSL::PKey::EC.new('prime256v1').generate_key
@ecdsa_sha2_nistp256 ||= OpenSSL::PKey::EC.generate('prime256v1')
end

def ecdsa_sha2_nistp384
@ecdsa_sha2_nistp384 ||= OpenSSL::PKey::EC.new('secp384r1').generate_key
@ecdsa_sha2_nistp384 ||= OpenSSL::PKey::EC.generate('secp384r1')
end

def ecdsa_sha2_nistp521
@ecdsa_sha2_nistp521 ||= OpenSSL::PKey::EC.new('secp521r1').generate_key
@ecdsa_sha2_nistp521 ||= OpenSSL::PKey::EC.generate('secp521r1')
end

def rsa_pk
Expand Down
12 changes: 12 additions & 0 deletions test/common.rb
Expand Up @@ -46,6 +46,18 @@ def P(*args)
Net::SSH::Packet.new(Net::SSH::Buffer.from(*args))
end

# DH key generate with OpenSSL::PKey::DH.new(512).to_pem
def dh_512bits_bn
OpenSSL::PKey::DH.new(
<<~DH_KEY
-----BEGIN DH PARAMETERS-----
MEYCQQDkZMgCTieW40x/bmCpf6m1XHERNnyOodot21UsJkCidr+T6aAcy/Oz4mWo
aYudmZZLQz7jhz0Ut2VQUw0Nz033AgEC
-----END DH PARAMETERS-----
DH_KEY
).p
end

class NetSSHTest < Minitest::Test
def assert_nothing_raised(&block)
yield
Expand Down
25 changes: 25 additions & 0 deletions test/openssl3.conf
@@ -0,0 +1,25 @@
openssl_conf = openssl_init

[openssl_init]
ssl_conf = ssl_sect
providers = provider_sect

[provider_sect]
default = default_sect
legacy = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 1

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
CipherString = DEFAULT@SECLEVEL=0
# system_default = system_default_sect
#
# [system_default_sect]
# Options = UnsafeLegacyRenegotiation
58 changes: 38 additions & 20 deletions test/test_buffer.rb
Expand Up @@ -319,16 +319,30 @@ def test_write_bignum_should_write_arguments_as_ssh_formatted_bignum_values_to_e
def test_write_dss_key_should_write_argument_to_end_of_buffer
buffer = new("start")

key = OpenSSL::PKey::DSA.new
if key.respond_to?(:set_pqg)
key.set_pqg(0xffeeddccbbaa9988, 0x7766554433221100, 0xffddbb9977553311)
key.set_key(0xeeccaa8866442200, nil)
else
key.p = 0xffeeddccbbaa9988
key.q = 0x7766554433221100
key.g = 0xffddbb9977553311
key.pub_key = 0xeeccaa8866442200
end
p = 0xffeeddccbbaa9988
q = 0x7766554433221100
g = 0xffddbb9977553311
pub_key = 0xeeccaa8866442200

asn1 = OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::ObjectId.new('DSA'),
OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Integer.new(p),
OpenSSL::ASN1::Integer.new(q),
OpenSSL::ASN1::Integer.new(g)
]
)
]
),
OpenSSL::ASN1::BitString.new(OpenSSL::ASN1::Integer.new(pub_key).to_der)
]
)

key = OpenSSL::PKey::DSA.new(asn1.to_der)

buffer.write_key(key)
assert_equal "start\0\0\0\7ssh-dss\0\0\0\011\0\xff\xee\xdd\xcc\xbb\xaa\x99\x88\0\0\0\010\x77\x66\x55\x44\x33\x22\x11\x00\0\0\0\011\0\xff\xdd\xbb\x99\x77\x55\x33\x11\0\0\0\011\0\xee\xcc\xaa\x88\x66\x44\x22\x00", buffer.to_s
Expand All @@ -337,13 +351,17 @@ def test_write_dss_key_should_write_argument_to_end_of_buffer
def test_write_rsa_key_should_write_argument_to_end_of_buffer
buffer = new("start")

key = OpenSSL::PKey::RSA.new
if key.respond_to?(:set_key)
key.set_key(0x7766554433221100, 0xffeeddccbbaa9988, nil)
else
key.e = 0xffeeddccbbaa9988
key.n = 0x7766554433221100
end
n = 0x7766554433221100
e = 0xffeeddccbbaa9988

asn1 = OpenSSL::ASN1::Sequence(
[
OpenSSL::ASN1::Integer(n),
OpenSSL::ASN1::Integer(e)
]
)

key = OpenSSL::PKey::RSA.new(asn1.to_der)

buffer.write_key(key)
assert_equal "start\0\0\0\7ssh-rsa\0\0\0\011\0\xff\xee\xdd\xcc\xbb\xaa\x99\x88\0\0\0\010\x77\x66\x55\x44\x33\x22\x11\x00", buffer.to_s
Expand Down Expand Up @@ -447,7 +465,7 @@ def random_dss
end

def random_ecdsa_sha2_nistp256
k = OpenSSL::PKey::EC.new('prime256v1').generate_key
k = OpenSSL::PKey::EC.generate('prime256v1')
buffer = Net::SSH::Buffer.from(:string, 'nistp256',
:string, k.public_key.to_bn.to_s(2))
key = yield(buffer)
Expand All @@ -456,7 +474,7 @@ def random_ecdsa_sha2_nistp256
end

def random_ecdsa_sha2_nistp384
k = OpenSSL::PKey::EC.new('secp384r1').generate_key
k = OpenSSL::PKey::EC.generate('secp384r1')
buffer = Net::SSH::Buffer.from(:string, 'nistp384',
:string, k.public_key.to_bn.to_s(2))
key = yield(buffer)
Expand All @@ -465,7 +483,7 @@ def random_ecdsa_sha2_nistp384
end

def random_ecdsa_sha2_nistp521
k = OpenSSL::PKey::EC.new('secp521r1').generate_key
k = OpenSSL::PKey::EC.generate('secp521r1')
buffer = Net::SSH::Buffer.from(:string, 'nistp521',
:string, k.public_key.to_bn.to_s(2))
key = yield(buffer)
Expand Down
17 changes: 9 additions & 8 deletions test/test_known_hosts.rb
Expand Up @@ -166,13 +166,14 @@ def with_config_file(lines: [], &block)
end

def rsa_key
key = OpenSSL::PKey::RSA.new
if key.respond_to?(:set_key)
key.set_key(0x7766554433221100, 0xffeeddccbbaa9988, nil)
else
key.e = 0xffeeddccbbaa9988
key.n = 0x7766554433221100
end
key
n = 0x7766554433221100
e = 0xffeeddccbbaa9988
asn1 = OpenSSL::ASN1::Sequence(
[
OpenSSL::ASN1::Integer(n),
OpenSSL::ASN1::Integer(e)
]
)
OpenSSL::PKey::RSA.new(asn1.to_der)
end
end
2 changes: 1 addition & 1 deletion test/transport/kex/test_curve25519_sha256.rb
Expand Up @@ -111,7 +111,7 @@ def server_key
end

def server_host_key
@server_host_key ||= OpenSSL::PKey::EC.new('prime256v1').generate_key
@server_host_key ||= OpenSSL::PKey::EC.generate('prime256v1')
end

def packet_data
Expand Down
2 changes: 1 addition & 1 deletion test/transport/kex/test_diffie_hellman_group1_sha1.rb
Expand Up @@ -133,7 +133,7 @@ def packet_data
end

def server_dh_pubkey
@server_dh_pubkey ||= bn(1234567890)
@server_dh_pubkey ||= OpenSSL::BN.new(dh_512bits_bn, 10)
end

def shared_secret
Expand Down
4 changes: 2 additions & 2 deletions test/transport/kex/test_ecdh_sha2_nistp256.rb
Expand Up @@ -109,11 +109,11 @@ def connection
end

def server_key
@server_key ||= OpenSSL::PKey::EC.new(ecparam).generate_key
@server_key ||= OpenSSL::PKey::EC.generate(ecparam)
end

def server_host_key
@server_host_key ||= OpenSSL::PKey::EC.new('prime256v1').generate_key
@server_host_key ||= OpenSSL::PKey::EC.generate('prime256v1')
end

def packet_data
Expand Down