net-ssh 8.0.0.rc4 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/pull_request_template.md +1 -0
- data/.github/workflows/changelog.yml +43 -0
- data/CHANGES.txt +30 -0
- data/CONTRIBUTING.md +35 -0
- data/README.md +58 -50
- data/Rakefile +48 -0
- data/changelog.d/README.md +1 -0
- data/lib/net/ssh/authentication/agent.rb +4 -1
- data/lib/net/ssh/authentication/key_manager.rb +22 -12
- data/lib/net/ssh/authentication/security_key.rb +2 -1
- data/lib/net/ssh/buffer.rb +2 -1
- data/lib/net/ssh/config.rb +6 -0
- data/lib/net/ssh/connection/channel.rb +4 -1
- data/lib/net/ssh/connection/session.rb +7 -4
- data/lib/net/ssh/errors.rb +10 -0
- data/lib/net/ssh/known_hosts.rb +18 -8
- data/lib/net/ssh/multiplex/client.rb +162 -0
- data/lib/net/ssh/multiplex/control_path.rb +120 -0
- data/lib/net/ssh/multiplex/proxy_transport.rb +218 -0
- data/lib/net/ssh/multiplex.rb +130 -0
- data/lib/net/ssh/proxy/jump.rb +40 -2
- data/lib/net/ssh/test.rb +2 -1
- data/lib/net/ssh/transport/algorithms.rb +33 -7
- data/lib/net/ssh/transport/hmac/sha1_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +2 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +8 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +45 -15
- data/lib/net/ssh/transport/openssl.rb +2 -1
- data/lib/net/ssh/transport/session.rb +17 -44
- data/lib/net/ssh/verifiers/always.rb +0 -3
- data/lib/net/ssh/version.rb +1 -1
- data/lib/net/ssh.rb +125 -51
- data/net-ssh.gemspec +1 -1
- data/rakelib/changelog.rb +229 -0
- data.tar.gz.sig +0 -0
- metadata +24 -8
- metadata.gz.sig +1 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fc22933c7ce50930b6118479820acb8d978d855baade0499b94065d7e245c016
|
|
4
|
+
data.tar.gz: 3340e9bd30ac3781da55ffdc0362626e32ad8b0c2db0b2352bf879dc6fe743bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 226a157e20beb49c008e4a3eb3e15a93ea23b7d0b2935f3c0fa4111d4e43815f6a77b0ef2f22e2bab7123f9410f99655459dc42b94c30ce63a295be77dc3b2ce
|
|
7
|
+
data.tar.gz: fb9269c31afc40374ef1b30cc58008d916cf41f3a633596e2fb04f924917f33e966c3b556df56f3cb10fbc24190d956ac9b59b2d57cb7b23204bded86f5316c6
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!-- After opening the PR, add a changelog.d/<PR number>.<type>.txt fragment (none, change, security, breaking or breaking-security) instead of editing CHANGES.txt; see CONTRIBUTING.md#changelog. -->
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Changelog
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened, labeled, unlabeled]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
changelog:
|
|
12
|
+
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
# HEAD is the PR merged into the base branch; HEAD^1 is the base it was merged into.
|
|
18
|
+
fetch-depth: 2
|
|
19
|
+
- name: Set up Ruby 3.1
|
|
20
|
+
uses: ruby/setup-ruby@v1
|
|
21
|
+
with:
|
|
22
|
+
ruby-version: 3.1
|
|
23
|
+
- name: Validate fragments
|
|
24
|
+
run: rake changelog:check
|
|
25
|
+
- name: Require a fragment
|
|
26
|
+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-changelog') }}
|
|
27
|
+
env:
|
|
28
|
+
PR: ${{ github.event.number }}
|
|
29
|
+
run: |
|
|
30
|
+
changed=$(git diff --name-only HEAD^1 HEAD)
|
|
31
|
+
if echo "$changed" | grep -x 'CHANGES\.txt' > /dev/null; then
|
|
32
|
+
echo "::error::Don't edit CHANGES.txt, add a changelog.d/$PR.<type>.txt fragment instead, see CONTRIBUTING.md#changelog"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
own=$(git diff --name-only --diff-filter=AMR HEAD^1 HEAD -- changelog.d/ | grep -E "^changelog\.d/$PR\.[a-z-]+(\.[0-9]+)?\.txt$" || true)
|
|
36
|
+
if [ -n "$own" ]; then
|
|
37
|
+
echo "Changelog fragments:"; echo "$own"
|
|
38
|
+
elif ! echo "$changed" | grep -v '^changelog\.d/' > /dev/null; then
|
|
39
|
+
echo "Only changelog.d/ changed, no fragment needed"
|
|
40
|
+
else
|
|
41
|
+
echo "::error::Add a changelog fragment named changelog.d/$PR.<type>.txt (use $PR.none.txt if nothing user-visible changed), see CONTRIBUTING.md#changelog"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
data/CHANGES.txt
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
=== 8.0.0
|
|
2
|
+
|
|
3
|
+
* No changes since 8.0.0 rc5.
|
|
4
|
+
|
|
5
|
+
=== 8.0.0 rc5
|
|
6
|
+
|
|
7
|
+
* BREAKING: Security: a custom `verify_host_key` verifier must now implement `verify_signature` (deprecated since 5.1.0) or ArgumentError is raised; such verifiers were previously wrapped so the server's host key signature was never checked [#1050]
|
|
8
|
+
* BREAKING: Unsupported key types now raise `Net::SSH::UnsupportedKeyType` (a `Net::SSH::Exception`) instead of `NotImplementedError`; code that rescued `NotImplementedError` around key loading or connecting should rescue the new class [#945, #1060]
|
|
9
|
+
* BREAKING: `Net::SSH.start` raises ArgumentError for option values that are `nil` or arrays containing `nil` (deprecated since 4.0.0); omit the option to use the default or ssh_config value, the error names a value that turns it off where one exists (e.g. `proxy: false`, `keys: []`, `config: false`). `password: nil` and `passphrase: nil` are still accepted [#458, #1053]
|
|
10
|
+
* BREAKING: removed the `:paranoid` option (deprecated since 4.2.0); use `:verify_host_key` with the same values. Passing `:paranoid` raises ArgumentError [#1050]
|
|
11
|
+
* BREAKING: removed the `verify_host_key` values `false`, `true`, `:very` and `:secure` (deprecated since 5.0.0); use `:never`, `:accept_new_or_local_tunnel`, `:accept_new` and `:always` respectively. The old values raise ArgumentError naming the replacement [#1050]
|
|
12
|
+
* BREAKING: `Net::SSH::HostKeyEntries::PubKey` (the known_hosts entries returned by `KnownHosts.search_for`) no longer forwards methods to the wrapped key (deprecated since 7.0.0); use `ssh_type`, `to_blob` or `matches_key?`, or the new `key` reader for the wrapped public key [#1050]
|
|
13
|
+
* Security: `append_all_supported_algorithms: true` no longer enables the `none` cipher and MAC; name them explicitly (`encryption: '+none'`, `hmac: '+none'`) to use them [#1051]
|
|
14
|
+
* Security: `diffie-hellman-group-exchange-sha1/sha256` now requires groups of at least 2048 bits and requests sizes from the negotiated ciphers, as OpenSSH since 7.2, and rejects invalid server groups and DH public values; like OpenSSH, the requested group size is capped at 4096 bits for Cisco servers. Pass `minimum_dh_bits: 1024` to connect to legacy servers that only offer 1024-bit groups. `minimum_dh_bits` values other than 1024 no longer fail key exchange with "could not verify server signature" [#1049]
|
|
15
|
+
* Security: `diffie-hellman-group14-sha1` is no longer offered by default for key exchange, as in OpenSSH since 8.2; add `KexAlgorithms +diffie-hellman-group14-sha1` in ssh_config (or `kex: '+diffie-hellman-group14-sha1'`) or pass `append_all_supported_algorithms: true` to re-enable [#705, #1042]
|
|
16
|
+
* Changelog entries are now added as `changelog.d/<PR number>.<type>.txt` fragment files instead of editing CHANGES.txt, and CI requires one per PR; see CONTRIBUTING.md [#1058]
|
|
17
|
+
* `Net::SSH.start(host, user, control_master: :auto)` reuses an already running OpenSSH ControlMaster found via `:control_path` or ssh_config `ControlPath`, falling back to a normal connection when there is none [#443, #1057]
|
|
18
|
+
* Default `max_win_size` is now 2 MB as in OpenSSH (was 128 KB), which avoids truncated output from some devices (e.g. Mikrotik); pass `max_win_size: 0x20000` for the old behaviour [#726, #1055]
|
|
19
|
+
* Added `hmac-sha1-etm@openssh.com`, offered by default after the SHA2 etm MACs as in OpenSSH [#985, #1056]
|
|
20
|
+
* `Net::SSH::Proxy::Jump` `options:` values may be an Array for ssh_config options that can be given more than once (`IdentityFile`, `CertificateFile`, `SendEnv`); each element is passed as its own `-o Key=value`, an empty Array passes nothing, and a `nil` value (alone or in an Array) raises ArgumentError as in `Net::SSH.start` [#1052]
|
|
21
|
+
* `ssh-rsa-cert-v00@openssh.com` host keys are deprecated and warn when named in `host_key`/`HostKeyAlgorithms` or negotiated; net-ssh cannot parse v00 certificates, use `ssh-rsa-cert-v01@openssh.com` or a modern key type [#1051]
|
|
22
|
+
* README: weak algorithms (CBC/3DES/Blowfish ciphers, `ssh-dss`, `diffie-hellman-group1-sha1`, old MACs, ...) stay available as opt-ins for legacy servers rather than being removed in 8.0 [#1051]
|
|
23
|
+
* An ssh-agent that fails while listing keys (e.g. closes the connection) is now skipped and key files are still tried, as in OpenSSH, instead of aborting authentication [#867, #1048]
|
|
24
|
+
* `%r` in a ProxyCommand now defaults to the connection's user, as in OpenSSH, instead of raising unless `:remote_user` is set [#881, #787, #1047]
|
|
25
|
+
* `Net::SSH.start` no longer modifies the options hash passed to it [#989, #1046]
|
|
26
|
+
* `Session#exec!` with a block now returns an empty string with `exitstatus` (like the non-block form) instead of `nil` [#848, #1045]
|
|
27
|
+
* ssh_config `KexAlgorithms` is now honoured and maps to `:kex`, including `+`, `-` and `^`; it was previously ignored [#1042]
|
|
28
|
+
* `Net::SSH::Proxy::Jump.new` accepts `options:`, a Hash of ssh_config options passed to the jump host's ssh command as escaped `-o Key=value` arguments, e.g. `options: { 'StrictHostKeyChecking' => 'no' }` [#915, #1041]
|
|
29
|
+
* `Net::SSH::Proxy::Jump` no longer fails with "unknown key" or substitutes the target host when the `config:` path contains `%` [#1041]
|
|
30
|
+
|
|
1
31
|
=== 8.0.0 rc4
|
|
2
32
|
|
|
3
33
|
* Security: RSA signatures using SHA-1 (`ssh-rsa`, `ssh-rsa-cert-v01@openssh.com`) are no longer offered by default for host keys or public key authentication, as in OpenSSH since 8.8; RSA keys keep working via rsa-sha2-256/512. For servers that only support SHA-1 add `HostKeyAlgorithms +ssh-rsa` / `PubkeyAcceptedAlgorithms +ssh-rsa` in ssh_config (or `host_key: '+ssh-rsa'` / `pubkey_algorithms: %w[+ssh-rsa]`), or pass `append_all_supported_algorithms: true` [#1039]
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Contributing to net-ssh
|
|
2
|
+
|
|
3
|
+
Run the unit tests with `bundle exec rake test` and the linter with `bundle exec rubocop`; see [README.md](README.md) and [DEVELOPMENT.md](DEVELOPMENT.md) for integration tests and debugging tips.
|
|
4
|
+
|
|
5
|
+
## Changelog
|
|
6
|
+
|
|
7
|
+
Don't edit `CHANGES.txt`. Instead, add a fragment file to `changelog.d/` in your PR; the release's version bump (`rake vbump:*`) moves all fragments into a new `=== <version>` section at the top of `CHANGES.txt` and deletes them.
|
|
8
|
+
|
|
9
|
+
A fragment is named `<number>.<type>.txt`, where `<number>` is the PR number (so open the PR first, then add the fragment), and contains a single UTF-8 paragraph: the entry as it should read in `CHANGES.txt`, without the bullet or prefix. Lines are joined, so it can be wrapped. If it doesn't end with a reference list such as `[#985, #1056]`, `[GHSA-xxxx-xxxx-xxxx]` or `[CVE-2024-12345, #1060]`, ` [#<number>]` is appended; write the list yourself to reference issues or advisories too.
|
|
10
|
+
|
|
11
|
+
| Type | Written as | Use for |
|
|
12
|
+
| ------------------- | ------------------------------ | ------------------------------------------------------------ |
|
|
13
|
+
| `breaking-security` | `* BREAKING: Security: <text>` | an incompatible change made for security |
|
|
14
|
+
| `breaking` | `* BREAKING: <text>` | an incompatible change |
|
|
15
|
+
| `security` | `* Security: <text>` | a security fix or hardening |
|
|
16
|
+
| `change` | `* <text>` | any other user-visible fix or feature |
|
|
17
|
+
| `none` | nothing | PRs with no user-visible change (tests, CI, docs, refactors) |
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
rake "changelog:new[1058,change,Session#exec! now returns the exit status]"
|
|
23
|
+
# changelog.d/1058.change.txt -> * Session#exec! now returns the exit status [#1058]
|
|
24
|
+
|
|
25
|
+
echo 'Removed the `:paranoid` option; use `:verify_host_key` [#1050]' > changelog.d/1050.breaking.txt
|
|
26
|
+
echo 'Reject packet lengths above 256 KB, as OpenSSH does [GHSA-pfqh-p9vh-wx4p]' > changelog.d/1060.security.txt
|
|
27
|
+
echo 'Custom verifiers must implement `verify_signature` [#1050]' > changelog.d/1050.breaking-security.txt
|
|
28
|
+
touch changelog.d/1061.none.txt
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For several entries from one PR add a suffix: `1050.breaking.txt`, `1050.breaking.2.txt` (`changelog:new` picks the next free one).
|
|
32
|
+
|
|
33
|
+
In a release section, entries are grouped as `BREAKING: Security:`, `BREAKING:`, `Security:`, then the rest; within a group fragments are ordered by number, newest first, followed by any hand-written entries from an `=== Unreleased` section in their written order. A final release with nothing to report still gets a `=== <version>` section saying `No changes since <previous version>.`
|
|
34
|
+
|
|
35
|
+
`rake changelog:check` validates the fragments and the `=== Unreleased` section, and `rake changelog:preview` prints the section the next release would add. CI fails a PR that edits `CHANGES.txt` or doesn't add or modify a `changelog.d/<PR number>.<type>.txt` fragment, unless it only touches `changelog.d/` or a maintainer adds the `skip-changelog` label; Dependabot PRs are skipped.
|
data/README.md
CHANGED
|
@@ -28,71 +28,75 @@ It allows you to write programs that invoke and interact with processes on remot
|
|
|
28
28
|
|
|
29
29
|
## Supported Algorithms
|
|
30
30
|
|
|
31
|
-
Net::SSH
|
|
32
|
-
We strongly recommend that you install a
|
|
31
|
+
Net::SSH only offers secure algorithms by default.
|
|
32
|
+
We strongly recommend that you install a server version that supports the latest algorithms.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Unsecure algoritms will definitely be removed in Net::SSH 8.*.
|
|
34
|
+
Weak algorithms are still supported as opt-ins, so legacy servers such as embedded routers and old network gear stay reachable. To enable one, prefix it with `+` in the matching option, e.g. `encryption: '+aes256-cbc'`, `hmac: '+hmac-sha1-96'`, `kex: '+diffie-hellman-group1-sha1'`, `host_key: '+ssh-dss'`, or in ssh_config with `Ciphers`, `MACs`, `KexAlgorithms`, `HostKeyAlgorithms` and `PubkeyAcceptedAlgorithms` (e.g. `Ciphers +aes256-cbc`). Passing `append_all_supported_algorithms: true` appends every supported algorithm except the `none` cipher and MAC, which are only used when named explicitly (e.g. `encryption: '+none'`, `hmac: '+none'`).
|
|
37
35
|
|
|
38
36
|
### Host Keys
|
|
39
37
|
|
|
40
|
-
| Name
|
|
41
|
-
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| ssh-
|
|
38
|
+
| Name | Support | Details |
|
|
39
|
+
|------------------------------------------|------------------------|----------|
|
|
40
|
+
| ssh-ed25519 | OK | Backed by Ruby OpenSSL raw Ed25519 APIs (`openssl >= 3.2.0`) |
|
|
41
|
+
| ssh-ed25519-cert-v01@openssh.com | OK | Backed by Ruby OpenSSL raw Ed25519 APIs (`openssl >= 3.2.0`) |
|
|
42
|
+
| ecdsa-sha2-nistp521/384/256 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
|
43
|
+
| ecdsa-sha2-nistp521/384/256-cert-v01@openssh.com | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
|
44
|
+
| rsa-sha2-512 | OK | |
|
|
45
|
+
| rsa-sha2-256 | OK | |
|
|
46
|
+
| ssh-rsa | Not offered by default | SHA-1 signatures, off by default as in OpenSSH 8.8; opt-in for legacy servers with `HostKeyAlgorithms +ssh-rsa` or `host_key: '+ssh-rsa'` |
|
|
47
|
+
| ssh-rsa-cert-v01@openssh.com | Not offered by default | SHA-1 signatures; opt-in for legacy servers |
|
|
48
|
+
| ssh-rsa-cert-v00@openssh.com | Deprecated | not offered by default, warns when used and will be removed; net-ssh cannot parse v00 certificates, use ssh-rsa-cert-v01@openssh.com or a modern key type |
|
|
49
|
+
| ssh-dss | Not offered by default | unsecure, off by default as in OpenSSH 7.0; opt-in for legacy servers |
|
|
50
50
|
|
|
51
51
|
RSA public key authentication likewise uses rsa-sha2-512 or rsa-sha2-256 by default; ssh-rsa and ssh-dss keys are only offered when enabled, e.g. with `PubkeyAcceptedAlgorithms +ssh-rsa` or `pubkey_algorithms: %w[+ssh-rsa]`.
|
|
52
52
|
|
|
53
53
|
### Key Exchange
|
|
54
54
|
|
|
55
|
-
| Name | Support
|
|
56
|
-
|
|
57
|
-
| curve25519-sha256 | OK
|
|
58
|
-
|
|
|
59
|
-
| ecdh-sha2-
|
|
60
|
-
| ecdh-sha2-
|
|
61
|
-
|
|
|
62
|
-
| diffie-hellman-
|
|
63
|
-
| diffie-hellman-
|
|
64
|
-
| diffie-hellman-
|
|
55
|
+
| Name | Support | Details |
|
|
56
|
+
|--------------------------------------|------------------------|----------|
|
|
57
|
+
| curve25519-sha256 | OK | Backed by Ruby OpenSSL raw X25519 APIs (`openssl >= 3.2.0`) |
|
|
58
|
+
| curve25519-sha256@libssh.org | OK | Backed by Ruby OpenSSL raw X25519 APIs (`openssl >= 3.2.0`) |
|
|
59
|
+
| ecdh-sha2-nistp521 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
|
60
|
+
| ecdh-sha2-nistp384 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
|
61
|
+
| ecdh-sha2-nistp256 | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
|
|
62
|
+
| diffie-hellman-group-exchange-sha256 | OK | |
|
|
63
|
+
| diffie-hellman-group14-sha256 | OK | |
|
|
64
|
+
| diffie-hellman-group14-sha1 | Not offered by default | SHA-1, off by default as in OpenSSH 8.2; opt-in for legacy servers with `KexAlgorithms +diffie-hellman-group14-sha1` or `kex: '+diffie-hellman-group14-sha1'` |
|
|
65
|
+
| diffie-hellman-group-exchange-sha1 | Not offered by default | unsecure; opt-in for legacy servers |
|
|
66
|
+
| diffie-hellman-group1-sha1 | Not offered by default | unsecure; opt-in for legacy servers |
|
|
65
67
|
|
|
66
68
|
### Encryption algorithms (ciphers)
|
|
67
69
|
|
|
68
|
-
| Name
|
|
69
|
-
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
| aes256-
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
70
|
+
| Name | Support | Details |
|
|
71
|
+
|-----------------------------------------|------------------------|----------|
|
|
72
|
+
| chacha20-poly1305@openssh.com | OK | Backed by Ruby OpenSSL ChaCha20 and Poly1305 APIs (`openssl >= 3.2.0`) |
|
|
73
|
+
| aes256-ctr / aes192-ctr / aes128-ctr | OK | |
|
|
74
|
+
| aes256-gcm@openssh.com / aes128-gcm@openssh.com | OK | |
|
|
75
|
+
| aes256-cbc / aes192-cbc / aes128-cbc | Not offered by default | unsecure; opt-in for legacy servers |
|
|
76
|
+
| rijndael-cbc@lysator.liu.se | Not offered by default | unsecure; opt-in for legacy servers |
|
|
77
|
+
| blowfish-ctr blowfish-cbc | Not offered by default | unsecure; opt-in for legacy servers |
|
|
78
|
+
| cast128-ctr cast128-cbc | Not offered by default | unsecure; opt-in for legacy servers |
|
|
79
|
+
| 3des-ctr 3des-cbc | Not offered by default | unsecure; opt-in for legacy servers |
|
|
80
|
+
| idea-cbc | Not offered by default | unsecure; opt-in for legacy servers |
|
|
81
|
+
| none | Not offered by default | no encryption; only used when named explicitly, not added by `append_all_supported_algorithms` |
|
|
79
82
|
|
|
80
83
|
### Message Authentication Code algorithms
|
|
81
84
|
|
|
82
|
-
| Name
|
|
83
|
-
|
|
84
|
-
| hmac-sha2-512-etm
|
|
85
|
-
| hmac-sha2-256-etm
|
|
86
|
-
| hmac-
|
|
87
|
-
| hmac-sha2-
|
|
88
|
-
| hmac-sha2-
|
|
89
|
-
| hmac-
|
|
90
|
-
| hmac-
|
|
91
|
-
| hmac-
|
|
92
|
-
| hmac-
|
|
93
|
-
| hmac-
|
|
94
|
-
| hmac-md5
|
|
95
|
-
|
|
|
85
|
+
| Name | Support | Details |
|
|
86
|
+
|-------------------------------|------------------------|----------|
|
|
87
|
+
| hmac-sha2-512-etm@openssh.com | OK | |
|
|
88
|
+
| hmac-sha2-256-etm@openssh.com | OK | |
|
|
89
|
+
| hmac-sha1-etm@openssh.com | OK | for backward compatibility |
|
|
90
|
+
| hmac-sha2-512 | OK | |
|
|
91
|
+
| hmac-sha2-256 | OK | |
|
|
92
|
+
| hmac-sha1 | OK | for backward compatibility |
|
|
93
|
+
| hmac-sha2-512-96 | Not offered by default | removed from the specification; opt-in for legacy servers |
|
|
94
|
+
| hmac-sha2-256-96 | Not offered by default | removed from the specification; opt-in for legacy servers |
|
|
95
|
+
| hmac-sha1-96 | Not offered by default | unsecure; opt-in for legacy servers |
|
|
96
|
+
| hmac-ripemd160 / hmac-ripemd160@openssh.com | Not offered by default | unsecure; opt-in for legacy servers |
|
|
97
|
+
| hmac-md5 | Not offered by default | unsecure; opt-in for legacy servers |
|
|
98
|
+
| hmac-md5-96 | Not offered by default | unsecure; opt-in for legacy servers |
|
|
99
|
+
| none | Not offered by default | no integrity protection; only used when named explicitly, not added by `append_all_supported_algorithms` |
|
|
96
100
|
|
|
97
101
|
## SYNOPSIS:
|
|
98
102
|
|
|
@@ -256,6 +260,10 @@ gem cert --add net-ssh-public_cert.pem
|
|
|
256
260
|
|
|
257
261
|
or `rake cert:update_public_when_expired`
|
|
258
262
|
|
|
263
|
+
## CONTRIBUTING
|
|
264
|
+
|
|
265
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md), including how to add a changelog entry.
|
|
266
|
+
|
|
259
267
|
## Security contact information
|
|
260
268
|
|
|
261
269
|
See [SECURITY.md](SECURITY.md)
|
data/Rakefile
CHANGED
|
@@ -28,6 +28,7 @@ CLEAN.include ['pkg', 'rdoc']
|
|
|
28
28
|
name = "net-ssh"
|
|
29
29
|
|
|
30
30
|
require_relative "lib/net/ssh/version"
|
|
31
|
+
require_relative "rakelib/changelog"
|
|
31
32
|
version = Net::SSH::Version::CURRENT
|
|
32
33
|
|
|
33
34
|
extra_files = %w[LICENSE.txt THANKS.txt CHANGES.txt]
|
|
@@ -109,6 +110,15 @@ def change_version(&block)
|
|
|
109
110
|
raise ArgumentError, "Cound not find line: TINY = \"#{tiny}\" in #{version_file}" unless found[:tiny] || new_tiny == tiny
|
|
110
111
|
end
|
|
111
112
|
|
|
113
|
+
begin
|
|
114
|
+
heading = Changelog.heading(Net::SSH::Version::MAJOR, Net::SSH::Version::MINOR, new_tiny, new_pre)
|
|
115
|
+
section = Changelog.new(__dir__).release(heading)
|
|
116
|
+
rescue StandardError
|
|
117
|
+
FileUtils.rm_f "#{version_file}.new"
|
|
118
|
+
raise
|
|
119
|
+
end
|
|
120
|
+
puts section ? "Added to CHANGES.txt:\n#{section}" : "Nothing to release for a pre-release, CHANGES.txt unchanged"
|
|
121
|
+
|
|
112
122
|
FileUtils.mv version_file, "#{version_file}.old"
|
|
113
123
|
FileUtils.mv "#{version_file}.new", version_file
|
|
114
124
|
end
|
|
@@ -148,6 +158,44 @@ namespace :vbump do
|
|
|
148
158
|
end
|
|
149
159
|
end
|
|
150
160
|
|
|
161
|
+
namespace :changelog do
|
|
162
|
+
changelog = Changelog.new(__dir__)
|
|
163
|
+
|
|
164
|
+
desc "Validate the fragments in changelog.d/"
|
|
165
|
+
task :check do
|
|
166
|
+
count = changelog.check.size
|
|
167
|
+
puts "#{count} valid changelog fragment#{'s' unless count == 1}"
|
|
168
|
+
rescue Changelog::Error => e
|
|
169
|
+
abort e.message
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
desc "Print the CHANGES.txt section the next version bump would write"
|
|
173
|
+
task :preview, [:heading] do |_t, args|
|
|
174
|
+
puts changelog.section(args[:heading] || "Unreleased") || "Nothing to release"
|
|
175
|
+
rescue Changelog::Error => e
|
|
176
|
+
abort e.message
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
desc "Create a fragment: rake \"changelog:new[1234,change,Text of the entry]\""
|
|
180
|
+
task :new, [:number, :type] do |_t, args|
|
|
181
|
+
abort "Usage: rake \"changelog:new[<PR number>,<#{Changelog::TYPES.keys.join('|')}>,<text>]\"" unless args[:number] && args[:type]
|
|
182
|
+
# Rake splits arguments on commas and strips the spaces around them, so take the text from the raw task string.
|
|
183
|
+
raw = Rake.application.top_level_tasks.find { |t| t.start_with?("changelog:new[") }
|
|
184
|
+
text = raw&.[](/\A[^\[]*\[[^,]*,[^,]*,\s*(.*)\]\z/m, 1) || args.extras.join(", ")
|
|
185
|
+
puts "Created #{changelog.new_fragment(args[:number], args[:type], text)}"
|
|
186
|
+
rescue Changelog::Error => e
|
|
187
|
+
abort e.message
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
desc "Write the fragments to CHANGES.txt under a heading, e.g. rake \"changelog:release[7.3.4]\" (vbump does this)"
|
|
191
|
+
task :release, [:heading] do |_t, args|
|
|
192
|
+
abort "Usage: rake \"changelog:release[<version heading>]\"" unless args[:heading]
|
|
193
|
+
puts changelog.release(args[:heading]) || "Nothing to release"
|
|
194
|
+
rescue Changelog::Error => e
|
|
195
|
+
abort e.message
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
151
199
|
namespace :rdoc do
|
|
152
200
|
desc "Update gh-pages branch"
|
|
153
201
|
task :publish do
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Changelog fragments: one `<PR number>.<type>.txt` file per user-visible change, assembled into `CHANGES.txt` when the version is bumped. See [CONTRIBUTING.md](../CONTRIBUTING.md#changelog).
|
|
@@ -152,7 +152,7 @@ module Net
|
|
|
152
152
|
key.extend(Comment)
|
|
153
153
|
key.comment = comment_str
|
|
154
154
|
identities.push key
|
|
155
|
-
rescue NotImplementedError => e
|
|
155
|
+
rescue Net::SSH::UnsupportedKeyType, NotImplementedError => e
|
|
156
156
|
error { "ignoring unimplemented key:#{e.message} #{comment_str}" }
|
|
157
157
|
end
|
|
158
158
|
end
|
|
@@ -256,6 +256,9 @@ module Net
|
|
|
256
256
|
def send_and_wait(type, *args)
|
|
257
257
|
send_packet(type, *args)
|
|
258
258
|
read_packet
|
|
259
|
+
rescue Errno::ECONNRESET, Errno::EPIPE => e
|
|
260
|
+
# Linux reports an agent that closes with our request unread as a reset, not EOF.
|
|
261
|
+
raise AgentClosedConnection, "agent closed the connection (#{e.class})"
|
|
259
262
|
end
|
|
260
263
|
|
|
261
264
|
# Returns +true+ if the parameter indicates a "failure" response from
|
|
@@ -124,18 +124,16 @@ module Net
|
|
|
124
124
|
|
|
125
125
|
user_identities = load_identities(prepared_identities, false, true)
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
yield key
|
|
138
|
-
end
|
|
127
|
+
agent_identities.each do |key|
|
|
128
|
+
corresponding_user_identity = user_identities.detect { |identity|
|
|
129
|
+
identity[:public_key] && identity[:public_key].to_blob == key.to_blob
|
|
130
|
+
}
|
|
131
|
+
# By identity: EC::Point#== raises TypeError when compared with other key types.
|
|
132
|
+
user_identities.reject! { |identity| identity.equal?(corresponding_user_identity) }
|
|
133
|
+
|
|
134
|
+
if !options[:keys_only] || corresponding_user_identity
|
|
135
|
+
known_identities[key] = { from: :agent, identity: key }
|
|
136
|
+
yield key
|
|
139
137
|
end
|
|
140
138
|
end
|
|
141
139
|
|
|
@@ -247,6 +245,18 @@ module Net
|
|
|
247
245
|
|
|
248
246
|
private
|
|
249
247
|
|
|
248
|
+
# Like OpenSSH's pubkey_prepare, an agent that fails to list its keys is
|
|
249
|
+
# dropped for the session so that key files are still tried.
|
|
250
|
+
def agent_identities
|
|
251
|
+
return [] unless agent
|
|
252
|
+
|
|
253
|
+
agent.identities
|
|
254
|
+
rescue AgentError => e
|
|
255
|
+
error { "could not get identities from agent: #{e.class} (#{e.message})" }
|
|
256
|
+
self.use_agent = false
|
|
257
|
+
[]
|
|
258
|
+
end
|
|
259
|
+
|
|
250
260
|
# Load keycerts from files and data.
|
|
251
261
|
def keycerts
|
|
252
262
|
keycert_files.map { |keycert_file| KeyFactory.load_public_key(keycert_file) } +
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'net/ssh/errors'
|
|
1
2
|
require 'net/ssh/authentication/pub_key_fingerprint'
|
|
2
3
|
|
|
3
4
|
module Net
|
|
@@ -35,7 +36,7 @@ module Net
|
|
|
35
36
|
application = buffer.read_string
|
|
36
37
|
new(type, public_key_data, application)
|
|
37
38
|
else
|
|
38
|
-
raise
|
|
39
|
+
raise Net::SSH::UnsupportedKeyType, "unsupported security key type `#{type}'"
|
|
39
40
|
end
|
|
40
41
|
end
|
|
41
42
|
|
data/lib/net/ssh/buffer.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'net/ssh/errors'
|
|
1
2
|
require 'net/ssh/transport/openssl'
|
|
2
3
|
|
|
3
4
|
require 'net/ssh/authentication/certificate'
|
|
@@ -343,7 +344,7 @@ module Net
|
|
|
343
344
|
Net::SSH::Authentication::SecurityKey::SK_SSH_ED25519
|
|
344
345
|
key = Net::SSH::Authentication::SecurityKey::PubKey.read_keyblob(type, self)
|
|
345
346
|
else
|
|
346
|
-
raise
|
|
347
|
+
raise Net::SSH::UnsupportedKeyType, "unsupported key type `#{type}'"
|
|
347
348
|
end
|
|
348
349
|
|
|
349
350
|
return key
|
data/lib/net/ssh/config.rb
CHANGED
|
@@ -15,6 +15,8 @@ module Net
|
|
|
15
15
|
# * Compression => :compression
|
|
16
16
|
# * CompressionLevel => :compression_level
|
|
17
17
|
# * ConnectTimeout => maps to the :timeout option
|
|
18
|
+
# * ControlPath => :control_path, used only when Net::SSH.start is given
|
|
19
|
+
# control_master: :auto; ControlMaster itself is not read
|
|
18
20
|
# * ForwardAgent => :forward_agent
|
|
19
21
|
# * GlobalKnownHostsFile => :global_known_hosts_file
|
|
20
22
|
# * HostBasedAuthentication => maps to the :auth_methods option
|
|
@@ -24,6 +26,7 @@ module Net
|
|
|
24
26
|
# * IdentityFile => maps to the :keys option
|
|
25
27
|
# * IdentityAgent => :identity_agent
|
|
26
28
|
# * IdentitiesOnly => :keys_only
|
|
29
|
+
# * KexAlgorithms => maps to the :kex option
|
|
27
30
|
# * CheckHostIP => :check_host_ip
|
|
28
31
|
# * Macs => maps to the :hmac option
|
|
29
32
|
# * PasswordAuthentication => maps to the :auth_methods option password
|
|
@@ -219,6 +222,7 @@ module Net
|
|
|
219
222
|
bindaddress: :bind_address,
|
|
220
223
|
compression: :compression,
|
|
221
224
|
compressionlevel: :compression_level,
|
|
225
|
+
controlpath: :control_path,
|
|
222
226
|
certificatefile: :keycerts,
|
|
223
227
|
connecttimeout: :timeout,
|
|
224
228
|
forwardagent: :forward_agent,
|
|
@@ -248,6 +252,8 @@ module Net
|
|
|
248
252
|
hash[:host_key] = value.split(/,/)
|
|
249
253
|
when :hostname
|
|
250
254
|
hash[:host_name] = value.gsub(/%h/, settings['host'])
|
|
255
|
+
when :kexalgorithms
|
|
256
|
+
hash[:kex] = value.split(/,/)
|
|
251
257
|
when :macs
|
|
252
258
|
hash[:hmac] = value.split(/,/)
|
|
253
259
|
when :serveralivecountmax
|
|
@@ -55,6 +55,9 @@ module Net
|
|
|
55
55
|
include Loggable
|
|
56
56
|
include Constants
|
|
57
57
|
|
|
58
|
+
# OpenSSH's CHAN_SES_WINDOW_DEFAULT; some servers (e.g. Mikrotik) truncate output with smaller windows (#726).
|
|
59
|
+
DEFAULT_MAX_WIN_SIZE = 0x200000
|
|
60
|
+
|
|
58
61
|
# The local id for this channel, assigned by the Net::SSH::Connection::Session instance.
|
|
59
62
|
attr_reader :local_id
|
|
60
63
|
|
|
@@ -109,7 +112,7 @@ module Net
|
|
|
109
112
|
# that time (see #do_open_confirmation).
|
|
110
113
|
#
|
|
111
114
|
# This also sets the default maximum packet size and maximum window size.
|
|
112
|
-
def initialize(connection, type, local_id, max_pkt_size = 0x8000, max_win_size =
|
|
115
|
+
def initialize(connection, type, local_id, max_pkt_size = 0x8000, max_win_size = DEFAULT_MAX_WIN_SIZE, &on_confirm_open)
|
|
113
116
|
self.logger = connection.logger
|
|
114
117
|
|
|
115
118
|
@connection = connection
|
|
@@ -82,7 +82,7 @@ module Net
|
|
|
82
82
|
@properties = (options[:properties] || {}).dup
|
|
83
83
|
|
|
84
84
|
@max_pkt_size = (options.key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000)
|
|
85
|
-
@max_win_size = (options.key?(:max_win_size) ? options[:max_win_size] :
|
|
85
|
+
@max_win_size = (options.key?(:max_win_size) ? options[:max_win_size] : Channel::DEFAULT_MAX_WIN_SIZE)
|
|
86
86
|
|
|
87
87
|
@keepalive = Keepalive.new(self)
|
|
88
88
|
|
|
@@ -429,7 +429,10 @@ module Net
|
|
|
429
429
|
#
|
|
430
430
|
# matches = ssh.exec!("grep something /some/files")
|
|
431
431
|
#
|
|
432
|
-
#
|
|
432
|
+
# With a block, output goes to the block and an empty string is returned,
|
|
433
|
+
# unless the block sets <tt>ch[:result]</tt>, which is returned instead.
|
|
434
|
+
# Either way the returned string has an exitstatus method to query the
|
|
435
|
+
# command's exit status.
|
|
433
436
|
def exec!(command, status: nil, &block)
|
|
434
437
|
block_or_concat = block || Proc.new do |ch, type, data|
|
|
435
438
|
ch[:result] ||= String.new
|
|
@@ -440,10 +443,10 @@ module Net
|
|
|
440
443
|
channel = exec(command, status: status, &block_or_concat)
|
|
441
444
|
channel.wait
|
|
442
445
|
|
|
443
|
-
channel[:result] ||= String.new unless block
|
|
444
446
|
channel[:result] &&= channel[:result].force_encoding("UTF-8") unless block
|
|
447
|
+
channel[:result] ||= String.new(encoding: Encoding::UTF_8)
|
|
445
448
|
|
|
446
|
-
StringWithExitstatus.new(channel[:result], status[:exit_code])
|
|
449
|
+
StringWithExitstatus.new(channel[:result], status[:exit_code])
|
|
447
450
|
end
|
|
448
451
|
|
|
449
452
|
# Enqueues a message to be sent to the server as soon as the socket is
|
data/lib/net/ssh/errors.rb
CHANGED
|
@@ -19,6 +19,16 @@ module Net
|
|
|
19
19
|
# timeouted unexpectedly.
|
|
20
20
|
class Timeout < Disconnect; end
|
|
21
21
|
|
|
22
|
+
# This exception is raised when a key blob has a key type that Net::SSH
|
|
23
|
+
# cannot parse.
|
|
24
|
+
class UnsupportedKeyType < Net::SSH::Exception; end
|
|
25
|
+
|
|
26
|
+
# Raised when a session connected through an OpenSSH ControlMaster (see the
|
|
27
|
+
# :control_master option of Net::SSH.start) is asked for something the
|
|
28
|
+
# master's proxy mode cannot carry, such as remote port forwarding, agent
|
|
29
|
+
# or X11 forwarding, or other global requests.
|
|
30
|
+
class NotSupportedOverControlMaster < Net::SSH::Exception; end
|
|
31
|
+
|
|
22
32
|
# This exception is primarily used internally, but if you have a channel
|
|
23
33
|
# request handler (see Net::SSH::Connection::Channel#on_request) that you
|
|
24
34
|
# want to fail in such a way that the server knows it failed, you can
|
data/lib/net/ssh/known_hosts.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'strscan'
|
|
2
2
|
require 'openssl'
|
|
3
|
-
require 'delegate'
|
|
4
3
|
require 'net/ssh/buffer'
|
|
5
4
|
require 'net/ssh/authentication/ed25519_loader'
|
|
6
5
|
|
|
@@ -8,8 +7,11 @@ module Net
|
|
|
8
7
|
module SSH
|
|
9
8
|
module HostKeyEntries
|
|
10
9
|
# regular public key entry
|
|
11
|
-
class PubKey
|
|
12
|
-
|
|
10
|
+
class PubKey
|
|
11
|
+
# The public key itself, e.g. an OpenSSL::PKey::PKey.
|
|
12
|
+
attr_reader :key
|
|
13
|
+
|
|
14
|
+
def initialize(key, comment: nil)
|
|
13
15
|
@key = key
|
|
14
16
|
@comment = comment
|
|
15
17
|
end
|
|
@@ -26,14 +28,22 @@ module Net
|
|
|
26
28
|
@key.to_blob
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
def __getobj__
|
|
30
|
-
Kernel.warn("Calling Net::SSH::Buffer methods on HostKeyEntries PubKey is deprecated")
|
|
31
|
-
@key
|
|
32
|
-
end
|
|
33
|
-
|
|
34
31
|
def matches_key?(server_key)
|
|
35
32
|
@key.ssh_type == server_key.ssh_type && @key.to_blob == server_key.to_blob
|
|
36
33
|
end
|
|
34
|
+
|
|
35
|
+
def method_missing(name, *args, &block)
|
|
36
|
+
return super unless @key.respond_to?(name)
|
|
37
|
+
|
|
38
|
+
raise NoMethodError.new(
|
|
39
|
+
"undefined method `#{name}' for #{self.class}; call it on #key, the wrapped public key",
|
|
40
|
+
name
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def respond_to_missing?(_name, _include_private = false)
|
|
45
|
+
false
|
|
46
|
+
end
|
|
37
47
|
end
|
|
38
48
|
|
|
39
49
|
# @cert-authority entry
|