net-ssh 7.1.0 → 7.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/ci.yml +8 -2
- data/.rubocop_todo.yml +1 -1
- data/CHANGES.txt +9 -0
- data/DEVELOPMENT.md +23 -0
- data/Dockerfile +1 -1
- data/Gemfile.norbnacl +12 -0
- data/README.md +19 -18
- data/lib/net/ssh/transport/algorithms.rb +27 -5
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
- data/lib/net/ssh/transport/cipher_factory.rb +26 -1
- data/lib/net/ssh/transport/identity_cipher.rb +8 -0
- data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
- data/lib/net/ssh/transport/packet_stream.rb +41 -20
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +2 -1
- data/net-ssh.gemspec +2 -0
- data.tar.gz.sig +0 -0
- metadata +24 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dc1c0937f59690bcefb72834ffc1012936e2555cd417b60214aaf07e7b4b829
|
4
|
+
data.tar.gz: '0857d1fe1296782d7c372836d20cc6217a0502c197ea76f1a0bfc6b9f1dc0cf1'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efe8268f0e6d1a4b0dbf60e2cd89b348504a843ed9092e8a378d844b93b000b1751f4eee226f2867d939c571b00e5332d201dd401b3d4241822f3236b6e2f5b7
|
7
|
+
data.tar.gz: 503688bf683aef5315c6748869760fc28e29cd4573782069b007216eed1d1d231ddab1d9dbf843daa60204fb365be7bb115f7490f84d1ce67b91bda987595b41
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
github: [mfazekas]
|
data/.github/workflows/ci.yml
CHANGED
@@ -4,10 +4,10 @@ on:
|
|
4
4
|
push: { branches: master }
|
5
5
|
jobs:
|
6
6
|
test:
|
7
|
-
runs-on: ubuntu-
|
7
|
+
runs-on: ubuntu-22.04
|
8
8
|
strategy:
|
9
9
|
matrix:
|
10
|
-
ruby-version: [2.6.
|
10
|
+
ruby-version: [2.6.10, 2.7.7, 3.0.5, 3.1.3, 3.2.1]
|
11
11
|
steps:
|
12
12
|
- uses: actions/checkout@v3
|
13
13
|
|
@@ -77,6 +77,12 @@ jobs:
|
|
77
77
|
env:
|
78
78
|
NET_SSH_RUN_INTEGRATION_TESTS: 1
|
79
79
|
CI: 1
|
80
|
+
- name: Run tests (without rbnacl)
|
81
|
+
run: bundle exec rake test
|
82
|
+
env:
|
83
|
+
BUNDLE_GEMFILE: ./Gemfile.norbnacl
|
84
|
+
NET_SSH_RUN_INTEGRATION_TESTS: 1
|
85
|
+
CI: 1
|
80
86
|
- name: Run Tests (without ed25519)
|
81
87
|
run: bundle exec rake test
|
82
88
|
env:
|
data/.rubocop_todo.yml
CHANGED
data/CHANGES.txt
CHANGED
data/DEVELOPMENT.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
### Development notes
|
2
|
+
|
3
|
+
## Building/running ssh server in debug mode
|
4
|
+
|
5
|
+
clone the openssh server from `https://github.com/openssh/openssh-portable`
|
6
|
+
|
7
|
+
```sh
|
8
|
+
brew install openssl
|
9
|
+
/usr/local/Cellar/openssl@3/3.1.0/bin/openssl
|
10
|
+
|
11
|
+
autoreconf
|
12
|
+
./configure --with-ssl-dir=/usr/local/Cellar/openssl@3/3.1.0/ --with-audit=debug --enable-debug CPPFLAGS="-DDEBUG -DPACKET_DEBUG" CFLAGS="-g -O0"
|
13
|
+
make
|
14
|
+
```
|
15
|
+
|
16
|
+
To run server in debug mode:
|
17
|
+
```sh
|
18
|
+
echo '#' > /tmp/sshd_config
|
19
|
+
ssh-keygen -t rsa -f /tmp/ssh_host_rsa_key
|
20
|
+
# /Users/boga/Work/OSS/NetSSH/openssh-portable/sshd -p 2222 -D -d -d -d -e -f /tmp/sshd_config
|
21
|
+
/Users/boga/Work/OSS/NetSSH/openssh-portable/sshd -p 2222 -D -d -d -d -e -f /tmp/sshd_config -h /tmp/ssh_host_rsa_key
|
22
|
+
|
23
|
+
```
|
data/Dockerfile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
ARG RUBY_VERSION=3.1
|
2
2
|
FROM ruby:${RUBY_VERSION}
|
3
3
|
|
4
|
-
RUN apt update && apt install -y openssh-server sudo netcat \
|
4
|
+
RUN apt update && apt install -y openssh-server sudo netcat-openbsd \
|
5
5
|
&& useradd --create-home --shell '/bin/bash' --comment 'NetSSH' 'net_ssh_1' \
|
6
6
|
&& useradd --create-home --shell '/bin/bash' --comment 'NetSSH' 'net_ssh_2' \
|
7
7
|
&& echo net_ssh_1:foopwd | chpasswd \
|
data/Gemfile.norbnacl
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
ENV['NET_SSH_NO_RBNACL'] = 'true'
|
4
|
+
# Specify your gem's dependencies in mygem.gemspec
|
5
|
+
gemspec
|
6
|
+
|
7
|
+
if ENV["CI"] && !Gem.win_platform?
|
8
|
+
gem 'simplecov', require: false, group: :test
|
9
|
+
gem 'codecov', require: false, group: :test
|
10
|
+
end
|
11
|
+
|
12
|
+
gem 'webrick', group: %i[development test] if RUBY_VERSION.split(".")[0].to_i >= 3
|
data/README.md
CHANGED
@@ -33,7 +33,7 @@ We strongly recommend that you install a servers's version that supports the lat
|
|
33
33
|
|
34
34
|
It is possible to return to the previous behavior by adding the option : `append_all_supported_algorithms: true`
|
35
35
|
|
36
|
-
Unsecure algoritms will definitely be removed in Net::SSH
|
36
|
+
Unsecure algoritms will definitely be removed in Net::SSH 8.*.
|
37
37
|
|
38
38
|
### Host Keys
|
39
39
|
|
@@ -44,7 +44,7 @@ Unsecure algoritms will definitely be removed in Net::SSH 7.*.
|
|
44
44
|
| ecdsa-sha2-nistp521 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
45
45
|
| ecdsa-sha2-nistp384 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
46
46
|
| ecdsa-sha2-nistp256 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
47
|
-
| ssh-dss | Deprecated in 6.0 | unsecure, will be removed in
|
47
|
+
| ssh-dss | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
48
48
|
|
49
49
|
### Key Exchange
|
50
50
|
|
@@ -54,9 +54,9 @@ Unsecure algoritms will definitely be removed in Net::SSH 7.*.
|
|
54
54
|
| ecdh-sha2-nistp521 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
55
55
|
| ecdh-sha2-nistp384 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
56
56
|
| ecdh-sha2-nistp256 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
57
|
-
| diffie-hellman-group1-sha1 | Deprecated in 6.0 | unsecure, will be removed in
|
57
|
+
| diffie-hellman-group1-sha1 | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
58
58
|
| diffie-hellman-group14-sha1 | OK | |
|
59
|
-
| diffie-hellman-group-exchange-sha1 | Deprecated in 6.0 | unsecure, will be removed in
|
59
|
+
| diffie-hellman-group-exchange-sha1 | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
60
60
|
| diffie-hellman-group-exchange-sha256 | OK | |
|
61
61
|
|
62
62
|
### Encryption algorithms (ciphers)
|
@@ -64,13 +64,14 @@ Unsecure algoritms will definitely be removed in Net::SSH 7.*.
|
|
64
64
|
| Name | Support | Details |
|
65
65
|
|--------------------------------------|-----------------------|----------|
|
66
66
|
| aes256-ctr / aes192-ctr / aes128-ctr | OK | |
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
| chacha20-poly1305@openssh.com | OK. | Requires the gem `rbnacl` |
|
68
|
+
| aes256-cbc / aes192-cbc / aes128-cbc | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
69
|
+
| rijndael-cbc@lysator.liu.se | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
70
|
+
| blowfish-ctr blowfish-cbc | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
71
|
+
| cast128-ctr cast128-cbc | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
72
|
+
| 3des-ctr 3des-cbc | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
73
|
+
| idea-cbc | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
74
|
+
| none | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
74
75
|
|
75
76
|
### Message Authentication Code algorithms
|
76
77
|
|
@@ -80,14 +81,14 @@ Unsecure algoritms will definitely be removed in Net::SSH 7.*.
|
|
80
81
|
| hmac-sha2-256-etm | OK | |
|
81
82
|
| hmac-sha2-512 | OK | |
|
82
83
|
| hmac-sha2-256 | OK | |
|
83
|
-
| hmac-sha2-512-96 | Deprecated in 6.0 | removed from the specification, will be removed in
|
84
|
-
| hmac-sha2-256-96 | Deprecated in 6.0 | removed from the specification, will be removed in
|
84
|
+
| hmac-sha2-512-96 | Deprecated in 6.0 | removed from the specification, will be removed in 8.0 |
|
85
|
+
| hmac-sha2-256-96 | Deprecated in 6.0 | removed from the specification, will be removed in 8.0 |
|
85
86
|
| hmac-sha1 | OK | for backward compatibility |
|
86
|
-
| hmac-sha1-96 | Deprecated in 6.0 | unsecure, will be removed in
|
87
|
-
| hmac-ripemd160 | Deprecated in 6.0 | unsecure, will be removed in
|
88
|
-
| hmac-md5 | Deprecated in 6.0 | unsecure, will be removed in
|
89
|
-
| hmac-md5-96 | Deprecated in 6.0 | unsecure, will be removed in
|
90
|
-
| none | Deprecated in 6.0 | unsecure, will be removed in
|
87
|
+
| hmac-sha1-96 | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
88
|
+
| hmac-ripemd160 | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
89
|
+
| hmac-md5 | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
90
|
+
| hmac-md5-96 | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
91
|
+
| none | Deprecated in 6.0 | unsecure, will be removed in 8.0 |
|
91
92
|
|
92
93
|
## SYNOPSIS:
|
93
94
|
|
@@ -51,6 +51,11 @@ module Net
|
|
51
51
|
hmac-sha1]
|
52
52
|
}.freeze
|
53
53
|
|
54
|
+
if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
|
55
|
+
DEFAULT_ALGORITHMS[:encryption].unshift(
|
56
|
+
'chacha20-poly1305@openssh.com'
|
57
|
+
)
|
58
|
+
end
|
54
59
|
if Net::SSH::Authentication::ED25519Loader::LOADED
|
55
60
|
DEFAULT_ALGORITHMS[:host_key].unshift(
|
56
61
|
'ssh-ed25519-cert-v01@openssh.com',
|
@@ -437,12 +442,13 @@ module Net
|
|
437
442
|
def exchange_keys
|
438
443
|
debug { "exchanging keys" }
|
439
444
|
|
445
|
+
need_bytes = kex_byte_requirement
|
440
446
|
algorithm = Kex::MAP[kex].new(self, session,
|
441
447
|
client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
|
442
448
|
server_version_string: session.server_version.version,
|
443
449
|
server_algorithm_packet: @server_packet,
|
444
450
|
client_algorithm_packet: @client_packet,
|
445
|
-
need_bytes:
|
451
|
+
need_bytes: need_bytes,
|
446
452
|
minimum_dh_bits: options[:minimum_dh_bits],
|
447
453
|
logger: logger)
|
448
454
|
result = algorithm.exchange_keys
|
@@ -464,11 +470,27 @@ module Net
|
|
464
470
|
|
465
471
|
parameters = { shared: secret, hash: hash, digester: digester }
|
466
472
|
|
467
|
-
cipher_client = CipherFactory.get(
|
468
|
-
|
473
|
+
cipher_client = CipherFactory.get(
|
474
|
+
encryption_client,
|
475
|
+
parameters.merge(iv: iv_client, key: key_client, encrypt: true)
|
476
|
+
)
|
477
|
+
cipher_server = CipherFactory.get(
|
478
|
+
encryption_server,
|
479
|
+
parameters.merge(iv: iv_server, key: key_server, decrypt: true)
|
480
|
+
)
|
469
481
|
|
470
|
-
mac_client =
|
471
|
-
|
482
|
+
mac_client =
|
483
|
+
if cipher_client.implicit_mac?
|
484
|
+
cipher_client.implicit_mac
|
485
|
+
else
|
486
|
+
HMAC.get(hmac_client, mac_key_client, parameters)
|
487
|
+
end
|
488
|
+
mac_server =
|
489
|
+
if cipher_server.implicit_mac?
|
490
|
+
cipher_server.implicit_mac
|
491
|
+
else
|
492
|
+
HMAC.get(hmac_server, mac_key_server, parameters)
|
493
|
+
end
|
472
494
|
|
473
495
|
session.configure_client cipher: cipher_client, hmac: mac_client,
|
474
496
|
compression: normalize_compression_name(compression_client),
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'rbnacl'
|
2
|
+
require 'net/ssh/loggable'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
|
+
module Transport
|
7
|
+
## Implements the chacha20-poly1305@openssh cipher
|
8
|
+
class ChaCha20Poly1305Cipher
|
9
|
+
include Net::SSH::Loggable
|
10
|
+
|
11
|
+
# Implicit HMAC, no need to do anything
|
12
|
+
class ImplicitHMac
|
13
|
+
def etm
|
14
|
+
# TODO: ideally this shouln't be called
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def key_length
|
19
|
+
64
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(encrypt:, key:)
|
24
|
+
@chacha_hdr = OpenSSL::Cipher.new("chacha20")
|
25
|
+
key_len = @chacha_hdr.key_len
|
26
|
+
@chacha_main = OpenSSL::Cipher.new("chacha20")
|
27
|
+
@poly = RbNaCl::OneTimeAuths::Poly1305
|
28
|
+
if key.size < key_len * 2
|
29
|
+
error { "chacha20_poly1305: keylength doesn't match" }
|
30
|
+
raise "chacha20_poly1305: keylength doesn't match"
|
31
|
+
end
|
32
|
+
if encrypt
|
33
|
+
@chacha_hdr.encrypt
|
34
|
+
@chacha_main.encrypt
|
35
|
+
else
|
36
|
+
@chacha_hdr.decrypt
|
37
|
+
@chacha_main.decrypt
|
38
|
+
end
|
39
|
+
main_key = key[0...key_len]
|
40
|
+
@chacha_main.key = main_key
|
41
|
+
hdr_key = key[key_len...(2 * key_len)]
|
42
|
+
@chacha_hdr.key = hdr_key
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_cipher_mac(payload, sequence_number)
|
46
|
+
iv_data = [0, 0, 0, sequence_number].pack("NNNN")
|
47
|
+
@chacha_main.iv = iv_data
|
48
|
+
poly_key = @chacha_main.update(([0] * 32).pack('C32'))
|
49
|
+
|
50
|
+
packet_length = payload.size
|
51
|
+
length_data = [packet_length].pack("N")
|
52
|
+
@chacha_hdr.iv = iv_data
|
53
|
+
packet = @chacha_hdr.update(length_data)
|
54
|
+
|
55
|
+
iv_data[0] = 1.chr
|
56
|
+
@chacha_main.iv = iv_data
|
57
|
+
unencrypted_data = payload
|
58
|
+
packet += @chacha_main.update(unencrypted_data)
|
59
|
+
|
60
|
+
packet += @poly.auth(poly_key, packet)
|
61
|
+
return packet
|
62
|
+
end
|
63
|
+
|
64
|
+
def read_length(data, sequence_number)
|
65
|
+
iv_data = [0, 0, 0, sequence_number].pack("NNNN")
|
66
|
+
@chacha_hdr.iv = iv_data
|
67
|
+
@chacha_hdr.update(data).unpack1("N")
|
68
|
+
end
|
69
|
+
|
70
|
+
def read_and_mac(data, mac, sequence_number)
|
71
|
+
iv_data = [0, 0, 0, sequence_number].pack("NNNN")
|
72
|
+
@chacha_main.iv = iv_data
|
73
|
+
poly_key = @chacha_main.update(([0] * 32).pack('C32'))
|
74
|
+
|
75
|
+
iv_data[0] = 1.chr
|
76
|
+
@chacha_main.iv = iv_data
|
77
|
+
unencrypted_data = @chacha_main.update(data[4..])
|
78
|
+
begin
|
79
|
+
ok = @poly.verify(poly_key, mac, data[0..])
|
80
|
+
raise Net::SSH::Exception, "corrupted hmac detected #{name}" unless ok
|
81
|
+
rescue RbNaCl::BadAuthenticatorError
|
82
|
+
raise Net::SSH::Exception, "corrupted hmac detected #{name}"
|
83
|
+
end
|
84
|
+
return unencrypted_data
|
85
|
+
end
|
86
|
+
|
87
|
+
def mac_length
|
88
|
+
16
|
89
|
+
end
|
90
|
+
|
91
|
+
def block_size
|
92
|
+
8
|
93
|
+
end
|
94
|
+
|
95
|
+
def name
|
96
|
+
"chacha20-poly1305@openssh.com"
|
97
|
+
end
|
98
|
+
|
99
|
+
def implicit_mac?
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
def implicit_mac
|
104
|
+
return ImplicitHMac.new
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.block_size
|
108
|
+
8
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.key_length
|
112
|
+
64
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Net
|
2
|
+
module SSH
|
3
|
+
module Transport
|
4
|
+
# Loads chacha20 poly1305 support which requires optinal dependency rbnacl
|
5
|
+
module ChaCha20Poly1305CipherLoader
|
6
|
+
begin
|
7
|
+
require 'net/ssh/transport/chacha20_poly1305_cipher'
|
8
|
+
LOADED = true
|
9
|
+
ERROR = nil
|
10
|
+
rescue LoadError => e
|
11
|
+
ERROR = e
|
12
|
+
LOADED = false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -2,6 +2,8 @@ require 'openssl'
|
|
2
2
|
require 'net/ssh/transport/ctr.rb'
|
3
3
|
require 'net/ssh/transport/key_expander'
|
4
4
|
require 'net/ssh/transport/identity_cipher'
|
5
|
+
require 'net/ssh/transport/chacha20_poly1305_cipher_loader'
|
6
|
+
require 'net/ssh/transport/openssl_cipher_extensions'
|
5
7
|
|
6
8
|
module Net
|
7
9
|
module SSH
|
@@ -29,13 +31,25 @@ module Net
|
|
29
31
|
'none' => 'none'
|
30
32
|
}
|
31
33
|
|
34
|
+
SSH_TO_CLASS =
|
35
|
+
if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
|
36
|
+
{
|
37
|
+
'chacha20-poly1305@openssh.com' => Net::SSH::Transport::ChaCha20Poly1305Cipher
|
38
|
+
}
|
39
|
+
else
|
40
|
+
{
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
32
44
|
# Returns true if the underlying OpenSSL library supports the given cipher,
|
33
45
|
# and false otherwise.
|
34
46
|
def self.supported?(name)
|
47
|
+
return true if SSH_TO_CLASS.key?(name)
|
48
|
+
|
35
49
|
ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
|
36
50
|
return true if ossl_name == "none"
|
37
51
|
|
38
|
-
return OpenSSL::Cipher.ciphers.include?(ossl_name)
|
52
|
+
return SSH_TO_CLASS.key?(name) || OpenSSL::Cipher.ciphers.include?(ossl_name)
|
39
53
|
end
|
40
54
|
|
41
55
|
# Retrieves a new instance of the named algorithm. The new instance
|
@@ -44,6 +58,13 @@ module Net
|
|
44
58
|
# cipher will be put into encryption or decryption mode, based on the
|
45
59
|
# value of the +encrypt+ parameter.
|
46
60
|
def self.get(name, options = {})
|
61
|
+
klass = SSH_TO_CLASS[name]
|
62
|
+
unless klass.nil?
|
63
|
+
key_len = klass.key_length
|
64
|
+
key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
|
65
|
+
return klass.new(encrypt: options[:encrypt], key: key)
|
66
|
+
end
|
67
|
+
|
47
68
|
ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
|
48
69
|
return IdentityCipher if ossl_name == "none"
|
49
70
|
|
@@ -53,6 +74,7 @@ module Net
|
|
53
74
|
|
54
75
|
cipher.padding = 0
|
55
76
|
|
77
|
+
cipher.extend(Net::SSH::Transport::OpenSSLCipherExtensions)
|
56
78
|
if name =~ /-ctr(@openssh.org)?$/
|
57
79
|
if ossl_name !~ /-ctr/
|
58
80
|
cipher.extend(Net::SSH::Transport::CTR)
|
@@ -75,6 +97,9 @@ module Net
|
|
75
97
|
# of the tuple.
|
76
98
|
# if :iv_len option is supplied the third return value will be ivlen
|
77
99
|
def self.get_lengths(name, options = {})
|
100
|
+
klass = SSH_TO_CLASS[name]
|
101
|
+
return [klass.key_length, klass.block_size] unless klass.nil?
|
102
|
+
|
78
103
|
ossl_name = SSH_TO_OSSL[name]
|
79
104
|
if ossl_name.nil? || ossl_name == "none"
|
80
105
|
result = [0, 0]
|
@@ -11,6 +11,10 @@ module Net
|
|
11
11
|
8
|
12
12
|
end
|
13
13
|
|
14
|
+
def key_length
|
15
|
+
0
|
16
|
+
end
|
17
|
+
|
14
18
|
# Returns an arbitrary integer.
|
15
19
|
def iv_len
|
16
20
|
4
|
@@ -50,6 +54,10 @@ module Net
|
|
50
54
|
def reset
|
51
55
|
self
|
52
56
|
end
|
57
|
+
|
58
|
+
def implicit_mac?
|
59
|
+
false
|
60
|
+
end
|
53
61
|
end
|
54
62
|
end
|
55
63
|
end
|
@@ -12,7 +12,7 @@ module Net
|
|
12
12
|
# module. It adds SSH encryption, compression, and packet validation, as
|
13
13
|
# per the SSH2 protocol. It also adds an abstraction for polling packets,
|
14
14
|
# to allow for both blocking and non-blocking reads.
|
15
|
-
module PacketStream
|
15
|
+
module PacketStream # rubocop:disable Metrics/ModuleLength
|
16
16
|
PROXY_COMMAND_HOST_IP = '<no hostip for proxy command>'.freeze
|
17
17
|
|
18
18
|
include BufferedIo
|
@@ -123,7 +123,7 @@ module Net
|
|
123
123
|
# Enqueues a packet to be sent, but does not immediately send the packet.
|
124
124
|
# The given payload is pre-processed according to the algorithms specified
|
125
125
|
# in the client state (compression, cipher, and hmac).
|
126
|
-
def enqueue_packet(payload)
|
126
|
+
def enqueue_packet(payload) # rubocop:disable Metrics/AbcSize
|
127
127
|
# try to compress the packet
|
128
128
|
payload = client.compress(payload)
|
129
129
|
|
@@ -144,7 +144,10 @@ module Net
|
|
144
144
|
|
145
145
|
padding = Array.new(padding_length) { rand(256) }.pack("C*")
|
146
146
|
|
147
|
-
if client.
|
147
|
+
if client.cipher.implicit_mac?
|
148
|
+
unencrypted_data = [padding_length, payload, padding].pack("CA*A*")
|
149
|
+
message = client.cipher.update_cipher_mac(unencrypted_data, client.sequence_number)
|
150
|
+
elsif client.hmac.etm
|
148
151
|
debug { "using encrypt-then-mac" }
|
149
152
|
|
150
153
|
# Encrypt padding_length, payload, and padding. Take MAC
|
@@ -225,7 +228,11 @@ module Net
|
|
225
228
|
data = read_available(minimum + aad_length)
|
226
229
|
|
227
230
|
# decipher it
|
228
|
-
if server.
|
231
|
+
if server.cipher.implicit_mac?
|
232
|
+
@packet_length = server.cipher.read_length(data[0...4], server.sequence_number)
|
233
|
+
@packet = Net::SSH::Buffer.new
|
234
|
+
@mac_data = data
|
235
|
+
elsif server.hmac.etm
|
229
236
|
@packet_length = data.unpack("N").first
|
230
237
|
@mac_data = data
|
231
238
|
@packet = Net::SSH::Buffer.new(server.update_cipher(data[aad_length..-1]))
|
@@ -238,31 +245,45 @@ module Net
|
|
238
245
|
need = @packet_length + 4 - aad_length - server.block_size
|
239
246
|
raise Net::SSH::Exception, "padding error, need #{need} block #{server.block_size}" if need % server.block_size != 0
|
240
247
|
|
241
|
-
|
248
|
+
if server.cipher.implicit_mac?
|
249
|
+
return nil if available < need + server.cipher.mac_length
|
250
|
+
else
|
251
|
+
return nil if available < need + server.hmac.mac_length # rubocop:disable Style/IfInsideElse
|
252
|
+
end
|
242
253
|
|
243
254
|
if need > 0
|
244
255
|
# read the remainder of the packet and decrypt it.
|
245
256
|
data = read_available(need)
|
246
|
-
@mac_data += data if server.hmac.etm
|
247
|
-
|
257
|
+
@mac_data += data if server.hmac.etm || server.cipher.implicit_mac?
|
258
|
+
unless server.cipher.implicit_mac?
|
259
|
+
@packet.append(
|
260
|
+
server.update_cipher(data)
|
261
|
+
)
|
262
|
+
end
|
248
263
|
end
|
249
264
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
265
|
+
if server.cipher.implicit_mac?
|
266
|
+
real_hmac = read_available(server.cipher.mac_length) || ""
|
267
|
+
@packet = Net::SSH::Buffer.new(server.cipher.read_and_mac(@mac_data, real_hmac, server.sequence_number))
|
268
|
+
padding_length = @packet.read_byte
|
269
|
+
payload = @packet.read(@packet_length - padding_length - 1)
|
270
|
+
else
|
271
|
+
# get the hmac from the tail of the packet (if one exists), and
|
272
|
+
# then validate it.
|
273
|
+
real_hmac = read_available(server.hmac.mac_length) || ""
|
256
274
|
|
257
|
-
|
275
|
+
@packet.append(server.final_cipher)
|
276
|
+
padding_length = @packet.read_byte
|
258
277
|
|
259
|
-
|
260
|
-
server.hmac.digest([server.sequence_number, @mac_data].pack("NA*"))
|
261
|
-
else
|
262
|
-
server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
|
263
|
-
end
|
264
|
-
raise Net::SSH::Exception, "corrupted hmac detected #{server.hmac.class}" if real_hmac != my_computed_hmac
|
278
|
+
payload = @packet.read(@packet_length - padding_length - 1)
|
265
279
|
|
280
|
+
my_computed_hmac = if server.hmac.etm
|
281
|
+
server.hmac.digest([server.sequence_number, @mac_data].pack("NA*"))
|
282
|
+
else
|
283
|
+
server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
|
284
|
+
end
|
285
|
+
raise Net::SSH::Exception, "corrupted hmac detected #{server.hmac.class}" if real_hmac != my_computed_hmac
|
286
|
+
end
|
266
287
|
# try to decompress the payload, in case compression is active
|
267
288
|
payload = server.decompress(payload)
|
268
289
|
|
data/lib/net/ssh/version.rb
CHANGED
@@ -49,14 +49,14 @@ module Net
|
|
49
49
|
MAJOR = 7
|
50
50
|
|
51
51
|
# The minor component of this version of the Net::SSH library
|
52
|
-
MINOR =
|
52
|
+
MINOR = 2
|
53
53
|
|
54
54
|
# The tiny component of this version of the Net::SSH library
|
55
55
|
TINY = 0
|
56
56
|
|
57
57
|
# The prerelease component of this version of the Net::SSH library
|
58
58
|
# nil allowed
|
59
|
-
PRE =
|
59
|
+
PRE = "rc1"
|
60
60
|
|
61
61
|
# The current version of the Net::SSH library as a Version instance
|
62
62
|
CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact)
|
data/lib/net/ssh.rb
CHANGED
@@ -64,7 +64,7 @@ module Net
|
|
64
64
|
# Net::SSH.start for a description of each option.
|
65
65
|
VALID_OPTIONS = %i[
|
66
66
|
auth_methods bind_address compression compression_level config
|
67
|
-
encryption forward_agent hmac host_key remote_user
|
67
|
+
encryption forward_agent hmac host_key identity_agent remote_user
|
68
68
|
keepalive keepalive_interval keepalive_maxcount kex keys key_data
|
69
69
|
keycerts languages logger paranoid password port proxy
|
70
70
|
rekey_blocks_limit rekey_limit rekey_packet_limit timeout verbose
|
@@ -192,6 +192,7 @@ module Net
|
|
192
192
|
# Defaults to %w(~/.ssh/known_hosts ~/.ssh/known_hosts2).
|
193
193
|
# * :use_agent => Set false to disable the use of ssh-agent. Defaults to
|
194
194
|
# true
|
195
|
+
# * :identity_agent => the path to the ssh-agent's UNIX socket
|
195
196
|
# * :verbose => how verbose to be (Logger verbosity constants, Logger::DEBUG
|
196
197
|
# is very verbose, Logger::FATAL is all but silent). Logger::FATAL is the
|
197
198
|
# default. The symbols :debug, :info, :warn, :error, and :fatal are also
|
data/net-ssh.gemspec
CHANGED
@@ -36,6 +36,8 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency('x25519') unless RUBY_PLATFORM == 'java'
|
37
37
|
end
|
38
38
|
|
39
|
+
spec.add_development_dependency('rbnacl', '~> 7.1') unless ENV['NET_SSH_NO_RBNACL']
|
40
|
+
|
39
41
|
spec.add_development_dependency "bundler", ">= 1.17"
|
40
42
|
spec.add_development_dependency "minitest", "~> 5.10"
|
41
43
|
spec.add_development_dependency "mocha", "~> 1.11.2"
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.2.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamis Buck
|
@@ -31,7 +31,7 @@ cert_chain:
|
|
31
31
|
v84waVXQ2i5M7pJaHVBF7DxxeW/q8W3VCnsq8vmmvULSThD18QqYGaFDJeN8sTR4
|
32
32
|
6tfjgZ6OvGSScvbCMHkCE9XjonE=
|
33
33
|
-----END CERTIFICATE-----
|
34
|
-
date: 2023-
|
34
|
+
date: 2023-07-14 00:00:00.000000000 Z
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bcrypt_pbkdf
|
@@ -75,6 +75,20 @@ dependencies:
|
|
75
75
|
- - ">="
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rbnacl
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '7.1'
|
85
|
+
type: :development
|
86
|
+
prerelease: false
|
87
|
+
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '7.1'
|
78
92
|
- !ruby/object:Gem::Dependency
|
79
93
|
name: bundler
|
80
94
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,6 +171,7 @@ extra_rdoc_files:
|
|
157
171
|
- README.md
|
158
172
|
files:
|
159
173
|
- ".dockerignore"
|
174
|
+
- ".github/FUNDING.yml"
|
160
175
|
- ".github/config/rubocop_linter_action.yml"
|
161
176
|
- ".github/workflows/ci-with-docker.yml"
|
162
177
|
- ".github/workflows/ci.yml"
|
@@ -165,10 +180,12 @@ files:
|
|
165
180
|
- ".rubocop.yml"
|
166
181
|
- ".rubocop_todo.yml"
|
167
182
|
- CHANGES.txt
|
183
|
+
- DEVELOPMENT.md
|
168
184
|
- Dockerfile
|
169
185
|
- Dockerfile.openssl3
|
170
186
|
- Gemfile
|
171
187
|
- Gemfile.noed25519
|
188
|
+
- Gemfile.norbnacl
|
172
189
|
- ISSUE_TEMPLATE.md
|
173
190
|
- LICENSE.txt
|
174
191
|
- Manifest
|
@@ -227,6 +244,8 @@ files:
|
|
227
244
|
- lib/net/ssh/test/script.rb
|
228
245
|
- lib/net/ssh/test/socket.rb
|
229
246
|
- lib/net/ssh/transport/algorithms.rb
|
247
|
+
- lib/net/ssh/transport/chacha20_poly1305_cipher.rb
|
248
|
+
- lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb
|
230
249
|
- lib/net/ssh/transport/cipher_factory.rb
|
231
250
|
- lib/net/ssh/transport/constants.rb
|
232
251
|
- lib/net/ssh/transport/ctr.rb
|
@@ -260,6 +279,7 @@ files:
|
|
260
279
|
- lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb
|
261
280
|
- lib/net/ssh/transport/key_expander.rb
|
262
281
|
- lib/net/ssh/transport/openssl.rb
|
282
|
+
- lib/net/ssh/transport/openssl_cipher_extensions.rb
|
263
283
|
- lib/net/ssh/transport/packet_stream.rb
|
264
284
|
- lib/net/ssh/transport/server_version.rb
|
265
285
|
- lib/net/ssh/transport/session.rb
|
@@ -288,9 +308,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
288
308
|
version: '2.6'
|
289
309
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
290
310
|
requirements:
|
291
|
-
- - "
|
311
|
+
- - ">"
|
292
312
|
- !ruby/object:Gem::Version
|
293
|
-
version:
|
313
|
+
version: 1.3.1
|
294
314
|
requirements: []
|
295
315
|
rubygems_version: 3.3.3
|
296
316
|
signing_key:
|
metadata.gz.sig
CHANGED
Binary file
|