summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml93
-rw-r--r--.gitignore2
-rw-r--r--.rubocop.yml13
-rw-r--r--.rubocop_todo.yml687
-rw-r--r--.travis.yml21
-rw-r--r--CHANGES.txt19
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.noed255192
-rw-r--r--README.md4
-rw-r--r--Rakefile1
-rw-r--r--lib/net/ssh.rb9
-rw-r--r--lib/net/ssh/authentication/agent.rb38
-rw-r--r--lib/net/ssh/authentication/certificate.rb21
-rw-r--r--lib/net/ssh/authentication/constants.rb1
-rw-r--r--lib/net/ssh/authentication/ed25519.rb18
-rw-r--r--lib/net/ssh/authentication/ed25519_loader.rb11
-rw-r--r--lib/net/ssh/authentication/key_manager.rb80
-rw-r--r--lib/net/ssh/authentication/methods/abstract.rb15
-rw-r--r--lib/net/ssh/authentication/methods/hostbased.rb8
-rw-r--r--lib/net/ssh/authentication/methods/keyboard_interactive.rb4
-rw-r--r--lib/net/ssh/authentication/methods/none.rb15
-rw-r--r--lib/net/ssh/authentication/methods/password.rb5
-rw-r--r--lib/net/ssh/authentication/methods/publickey.rb72
-rw-r--r--lib/net/ssh/authentication/pageant.rb194
-rw-r--r--lib/net/ssh/authentication/pub_key_fingerprint.rb4
-rw-r--r--lib/net/ssh/authentication/session.rb35
-rw-r--r--lib/net/ssh/buffer.rb21
-rw-r--r--lib/net/ssh/buffered_io.rb49
-rw-r--r--lib/net/ssh/config.rb53
-rw-r--r--lib/net/ssh/connection/channel.rb167
-rw-r--r--lib/net/ssh/connection/constants.rb4
-rw-r--r--lib/net/ssh/connection/event_loop.rb54
-rw-r--r--lib/net/ssh/connection/keepalive.rb24
-rw-r--r--lib/net/ssh/connection/session.rb215
-rw-r--r--lib/net/ssh/connection/term.rb114
-rw-r--r--lib/net/ssh/errors.rb24
-rw-r--r--lib/net/ssh/key_factory.rb15
-rw-r--r--lib/net/ssh/known_hosts.rb98
-rw-r--r--lib/net/ssh/loggable.rb17
-rw-r--r--lib/net/ssh/packet.rb2
-rw-r--r--lib/net/ssh/prompt.rb20
-rw-r--r--lib/net/ssh/proxy/command.rb2
-rw-r--r--lib/net/ssh/proxy/errors.rb6
-rw-r--r--lib/net/ssh/proxy/http.rb38
-rw-r--r--lib/net/ssh/proxy/https.rb18
-rw-r--r--lib/net/ssh/proxy/jump.rb18
-rw-r--r--lib/net/ssh/proxy/socks4.rb6
-rw-r--r--lib/net/ssh/proxy/socks5.rb8
-rw-r--r--lib/net/ssh/service/forward.rb14
-rw-r--r--lib/net/ssh/test.rb9
-rw-r--r--lib/net/ssh/test/channel.rb50
-rw-r--r--lib/net/ssh/test/extensions.rb70
-rw-r--r--lib/net/ssh/test/kex.rb14
-rw-r--r--lib/net/ssh/test/local_packet.rb2
-rw-r--r--lib/net/ssh/test/packet.rb6
-rw-r--r--lib/net/ssh/test/remote_packet.rb14
-rw-r--r--lib/net/ssh/test/script.rb52
-rw-r--r--lib/net/ssh/test/socket.rb27
-rw-r--r--lib/net/ssh/transport/algorithms.rb31
-rw-r--r--lib/net/ssh/transport/cipher_factory.rb56
-rw-r--r--lib/net/ssh/transport/constants.rb6
-rw-r--r--lib/net/ssh/transport/ctr.rb14
-rw-r--r--lib/net/ssh/transport/hmac.rb24
-rw-r--r--lib/net/ssh/transport/hmac/abstract.rb9
-rw-r--r--lib/net/ssh/transport/hmac/md5.rb2
-rw-r--r--lib/net/ssh/transport/hmac/md5_96.rb2
-rw-r--r--lib/net/ssh/transport/hmac/none.rb2
-rw-r--r--lib/net/ssh/transport/hmac/ripemd160.rb2
-rw-r--r--lib/net/ssh/transport/hmac/sha1.rb2
-rw-r--r--lib/net/ssh/transport/hmac/sha1_96.rb2
-rw-r--r--lib/net/ssh/transport/identity_cipher.rb24
-rw-r--r--lib/net/ssh/transport/kex.rb14
-rw-r--r--lib/net/ssh/transport/kex/abstract.rb17
-rw-r--r--lib/net/ssh/transport/kex/abstract5656.rb2
-rw-r--r--lib/net/ssh/transport/kex/curve25519_sha256.rb3
-rw-r--r--lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb8
-rw-r--r--lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb11
-rw-r--r--lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb8
-rw-r--r--lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb3
-rw-r--r--lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb2
-rw-r--r--lib/net/ssh/transport/key_expander.rb15
-rw-r--r--lib/net/ssh/transport/openssl.rb56
-rw-r--r--lib/net/ssh/transport/packet_stream.rb5
-rw-r--r--lib/net/ssh/transport/server_version.rb33
-rw-r--r--lib/net/ssh/transport/session.rb16
-rw-r--r--lib/net/ssh/transport/state.rb86
-rw-r--r--lib/net/ssh/verifiers/accept_new.rb2
-rw-r--r--lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb3
-rw-r--r--lib/net/ssh/verifiers/always.rb10
-rw-r--r--lib/net/ssh/verifiers/never.rb2
-rw-r--r--lib/net/ssh/version.rb4
-rw-r--r--net-ssh-public_cert.pem16
-rw-r--r--net-ssh.gemspec4
-rwxr-xr-xsupport/ssh_tunnel_bug.rb6
-rw-r--r--test/authentication/methods/common.rb23
-rw-r--r--test/authentication/methods/test_abstract.rb3
-rw-r--r--test/authentication/methods/test_hostbased.rb30
-rw-r--r--test/authentication/methods/test_keyboard_interactive.rb70
-rw-r--r--test/authentication/methods/test_none.rb24
-rw-r--r--test/authentication/methods/test_password.rb46
-rw-r--r--test/authentication/methods/test_publickey.rb89
-rw-r--r--test/authentication/test_agent.rb65
-rw-r--r--test/authentication/test_certificate.rb8
-rw-r--r--test/authentication/test_ed25519.rb12
-rw-r--r--test/authentication/test_key_manager.rb8
-rw-r--r--test/authentication/test_session.rb10
-rw-r--r--test/common.rb12
-rw-r--r--test/connection/test_channel.rb63
-rw-r--r--test/connection/test_session.rb61
-rw-r--r--test/integration/Vagrantfile5
-rw-r--r--test/integration/common.rb72
-rw-r--r--test/integration/mitm_server.rb4
-rw-r--r--test/integration/playbook.yml37
-rw-r--r--test/integration/test_agent.rb2
-rw-r--r--test/integration/test_cert_host_auth.rb94
-rw-r--r--test/integration/test_cert_user_auth.rb8
-rw-r--r--test/integration/test_channel.rb51
-rw-r--r--test/integration/test_curve25519sha256.rb23
-rw-r--r--test/integration/test_ed25519_pkeys.rb28
-rw-r--r--test/integration/test_encoding.rb2
-rw-r--r--test/integration/test_forward.rb256
-rw-r--r--test/integration/test_hmac_etm.rb38
-rw-r--r--test/integration/test_http_proxy.rb4
-rw-r--r--test/integration/test_id_rsa_keys.rb14
-rw-r--r--test/integration/test_proxy.rb15
-rw-r--r--test/manual/test_pageant.rb4
-rw-r--r--test/start/test_transport.rb10
-rw-r--r--test/start/test_user_nil.rb2
-rw-r--r--test/test/test_test.rb2
-rw-r--r--test/test_all.rb2
-rw-r--r--test/test_buffer.rb3
-rw-r--r--test/test_buffered_io.rb2
-rw-r--r--test/test_config.rb82
-rw-r--r--test/test_key_factory.rb4
-rw-r--r--test/test_known_hosts.rb72
-rw-r--r--test/transport/hmac/test_md5.rb18
-rw-r--r--test/transport/hmac/test_md5_96.rb12
-rw-r--r--test/transport/hmac/test_none.rb14
-rw-r--r--test/transport/hmac/test_ripemd160.rb14
-rw-r--r--test/transport/hmac/test_sha1.rb16
-rw-r--r--test/transport/hmac/test_sha1_96.rb12
-rw-r--r--test/transport/hmac/test_sha2_256.rb1
-rw-r--r--test/transport/hmac/test_sha2_256_96.rb10
-rw-r--r--test/transport/hmac/test_sha2_256_etm.rb1
-rw-r--r--test/transport/hmac/test_sha2_512.rb1
-rw-r--r--test/transport/hmac/test_sha2_512_96.rb10
-rw-r--r--test/transport/hmac/test_sha2_512_etm.rb1
-rw-r--r--test/transport/kex/test_curve25519_sha256.rb4
-rw-r--r--test/transport/kex/test_diffie_hellman_group14_sha1.rb7
-rw-r--r--test/transport/kex/test_diffie_hellman_group14_sha256.rb16
-rw-r--r--test/transport/kex/test_diffie_hellman_group1_sha1.rb30
-rw-r--r--test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb63
-rw-r--r--test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb8
-rw-r--r--test/transport/kex/test_ecdh_sha2_nistp256.rb4
-rw-r--r--test/transport/kex/test_ecdh_sha2_nistp384.rb2
-rw-r--r--test/transport/kex/test_ecdh_sha2_nistp521.rb2
-rw-r--r--test/transport/test_algorithms.rb117
-rw-r--r--test/transport/test_cipher_factory.rb36
-rw-r--r--test/transport/test_hmac.rb6
-rw-r--r--test/transport/test_identity_cipher.rb2
-rw-r--r--test/transport/test_packet_stream.rb14
-rw-r--r--test/transport/test_server_version.rb2
-rw-r--r--test/transport/test_session.rb4
-rw-r--r--test/transport/test_state.rb12
-rw-r--r--test/verifiers/test_always.rb12
-rw-r--r--test/win_integration/test_pageant.rb13
166 files changed, 2726 insertions, 2205 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..363814f
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,93 @@
+name: CI
+on: [push, pull_request]
+jobs:
+ test:
+ runs-on: ubuntu-18.04
+ continue-on-error: ${{ matrix.flaky }}
+ strategy:
+ matrix:
+ ruby-version: [2.7.2, 2.6.6, 3.0.1]
+ flaky: [false]
+ include:
+ - ruby-version: 2.5.8
+ flaky: true
+ steps:
+ - uses: actions/checkout@v1
+
+ - name: Set up Ruby ${{ matrix.ruby-version }}
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: ${{ matrix.ruby-version }}
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+
+ - name: Cache bundler
+ uses: actions/cache@v1
+ id: bundler-cache
+ with:
+ path: vendor/bundle
+ key: ${{ runner.os }}-${{ matrix.ruby-version }}-gem-v3-${{ hashFiles('**/Gemfile') }}-${{ hashFiles('**/net-ssh.gemspec') }}
+ restore-keys: |
+ ${{ runner.os }}-${{ matrix.ruby-version }}-gem-v3-
+
+ - name: Cache pip
+ uses: actions/cache@v1
+ id: pip-cache
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-v1
+ restore-keys: |
+ ${{ runner.os }}-pip-v1
+ - name: Bundle install
+ run: |
+ gem install bundler
+ bundle config set path 'vendor/bundle'
+ bundle config set --local path 'vendor/bundle'
+ bundle install --jobs 4 --retry 3 --path vendor/bundle
+ BUNDLE_GEMFILE=./Gemfile.noed25519 bundle install --jobs 4 --retry 3 --path vendor/bundle
+ env:
+ BUNDLE_PATH: vendor/bundle
+
+ - name: Add to etc/hosts
+ run: |
+ sudo echo "127.0.0.1 gateway.netssh" | sudo tee -a /etc/hosts
+ - name: Check sshd_config
+ run: sudo cat '/etc/ssh/sshd_config' || true
+ - name: Check sshd_config2
+ run: sudo cat /etc/ssh/sshd_config.d/*.conf || true
+ - name: Check sshd pid
+ run: sudo ps aux | grep sshd
+ - name: Ansible install
+ run: |
+ python -m pip install --upgrade pip
+ pip install ansible urllib3 pyOpenSSL ndg-httpsclient pyasn1
+ ansible-galaxy install rvm.ruby
+ pwd
+ uname -a
+ export
+ who am i
+ ansible-playbook ./test/integration/playbook.yml -i "localhost," --become -c local -e 'no_rvm=true' -e 'myuser=runner' -e 'mygroup=runner' -e 'homedir=/home/runner'
+ - name: Check sshd_config
+ run: sudo cat '/etc/ssh/sshd_config' || true
+ - name: Check sshd pid
+ run: sudo ps aux | grep sshd
+ - name: Check sshd_config2
+ run: sudo cat /etc/ssh/sshd_config.d/*.conf || true
+ - name: Run Tests
+ run: bundle exec rake test
+ env:
+ NET_SSH_RUN_INTEGRATION_TESTS: 1
+ CI: 1
+ - name: Run Tests (without ed25519)
+ run: bundle exec rake test
+ env:
+ BUNDLE_GEMFILE: ./Gemfile.noed25519
+ NET_SSH_RUN_INTEGRATION_TESTS: 1
+ CI: 1
+ - name: Run test helper test
+ run: bundle exec rake test_test
+ - name: Rubocop
+ if: matrix.ruby-version == '3.0.1'
+ run: bundle exec rubocop --fail-level C -f s
diff --git a/.gitignore b/.gitignore
index b02057e..acb2b39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,5 @@ test/integration/.vagrant
test/integration/playbook.retry
.byebug_history
+
+tryout
diff --git a/.rubocop.yml b/.rubocop.yml
index 41e4915..aa0c0cb 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,11 +1,22 @@
+AllCops:
+ Exclude:
+ - 'tryout/**/*'
+ - "vendor/**/.*"
+ - "vendor/**/*"
+ NewCops: enable
+ TargetRubyVersion: 2.5
+
inherit_from: .rubocop_todo.yml
Style/DoubleNegation:
Exclude:
- 'lib/net/ssh/key_factory.rb'
-Metrics/LineLength:
+Layout/LineLength:
Max: 150
Exclude:
- 'test/**/*.rb'
- 'net-ssh.gemspec'
+
+Style/EmptyLiteral:
+ Enabled: false
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index a1b7067..0cec116 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,71 +1,20 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2019-09-10 17:13:26 +0200 using RuboCop version 0.74.0.
+# on 2021-10-25 13:17:23 UTC using RuboCop version 1.22.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 76
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, IndentationWidth.
-# SupportedStyles: with_first_argument, with_fixed_indentation
-Layout/AlignArguments:
- Enabled: false
-
-# Offense count: 57
-# Cop supports --auto-correct.
-# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
-# SupportedHashRocketStyles: key, separator, table
-# SupportedColonStyles: key, separator, table
-# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
-Layout/AlignHash:
- Exclude:
- - 'lib/net/ssh/key_factory.rb'
- - 'lib/net/ssh/transport/cipher_factory.rb'
- - 'lib/net/ssh/transport/hmac.rb'
- - 'lib/net/ssh/transport/kex.rb'
- - 'test/test_config.rb'
-
-# Offense count: 70
-# Cop supports --auto-correct.
-Layout/EmptyLineAfterGuardClause:
- Enabled: false
-
-# Offense count: 170
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
-Layout/EmptyLinesAroundModuleBody:
- Enabled: false
-
-# Offense count: 2
+# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
-# SupportedStyles: special_inside_parentheses, consistent, align_brackets
-Layout/IndentFirstArrayElement:
- Exclude:
- - 'lib/net/ssh/transport/openssl.rb'
-
-# Offense count: 3
-# Cop supports --auto-correct.
-Layout/LeadingBlankLines:
- Exclude:
- - 'Rakefile'
- - 'lib/net/ssh/authentication/pub_key_fingerprint.rb'
- - 'support/arcfour_check.rb'
-
-# Offense count: 14
-# Cop supports --auto-correct.
-# Configuration parameters: AllowDoxygenCommentStyle.
-Layout/LeadingCommentSpace:
+# SupportedStyles: aligned, indented
+Layout/LineEndStringConcatenationIndentation:
Exclude:
- - 'test/integration/test_ed25519_pkeys.rb'
- - 'test/integration/test_forward.rb'
- - 'test/integration/test_id_rsa_keys.rb'
- - 'test/integration/test_proxy.rb'
+ - 'lib/net/ssh/transport/algorithms.rb'
-# Offense count: 23
+# Offense count: 7
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented
@@ -75,31 +24,8 @@ Layout/MultilineOperationIndentation:
- 'lib/net/ssh/proxy/https.rb'
- 'lib/net/ssh/transport/algorithms.rb'
- 'lib/net/ssh/transport/state.rb'
- - 'lib/net/ssh/verifiers/always.rb'
- - 'test/authentication/methods/test_hostbased.rb'
- - 'test/authentication/methods/test_publickey.rb'
-# Offense count: 16
-# Cop supports --auto-correct.
-Layout/SpaceAfterColon:
- Exclude:
- - 'lib/net/ssh/authentication/ed25519.rb'
- - 'test/integration/test_ed25519_pkeys.rb'
- - 'test/verifiers/test_always.rb'
-
-# Offense count: 281
-# Cop supports --auto-correct.
-Layout/SpaceAfterComma:
- Enabled: false
-
-# Offense count: 136
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: space, no_space
-Layout/SpaceAroundEqualsInParameterDefault:
- Enabled: false
-
-# Offense count: 10
+# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
@@ -109,9 +35,6 @@ Layout/SpaceInsideBlockBraces:
- 'lib/net/ssh/authentication/session.rb'
- 'lib/net/ssh/transport/ctr.rb'
- 'support/ssh_tunnel_bug.rb'
- - 'test/authentication/test_agent.rb'
- - 'test/authentication/test_key_manager.rb'
- - 'test/start/test_user_nil.rb'
# Offense count: 6
# Cop supports --auto-correct.
@@ -122,18 +45,18 @@ Layout/SpaceInsideReferenceBrackets:
Exclude:
- 'lib/net/ssh/transport/algorithms.rb'
-# Offense count: 17
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: final_newline, final_blank_line
-Layout/TrailingBlankLines:
- Enabled: false
-
-# Offense count: 739
+# Offense count: 11
# Cop supports --auto-correct.
-# Configuration parameters: AllowInHeredoc.
-Layout/TrailingWhitespace:
- Enabled: false
+Lint/AmbiguousOperatorPrecedence:
+ Exclude:
+ - 'lib/net/ssh/authentication/certificate.rb'
+ - 'lib/net/ssh/config.rb'
+ - 'lib/net/ssh/loggable.rb'
+ - 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb'
+ - 'lib/net/ssh/transport/openssl.rb'
+ - 'lib/net/ssh/transport/state.rb'
+ - 'lib/net/ssh/version.rb'
+ - 'test/integration/test_proxy.rb'
# Offense count: 4
# Configuration parameters: AllowSafeAssignment.
@@ -144,76 +67,124 @@ Lint/AssignmentInCondition:
- 'lib/net/ssh/proxy/command.rb'
# Offense count: 1
-Lint/EmptyWhen:
+# Configuration parameters: AllowedMethods.
+# AllowedMethods: enums
+Lint/ConstantDefinitionInBlock:
Exclude:
- - 'lib/net/ssh/config.rb'
+ - 'test/transport/test_cipher_factory.rb'
-# Offense count: 9
-# Configuration parameters: AllowComments.
-Lint/HandleExceptions:
+# Offense count: 1
+# Cop supports --auto-correct.
+Lint/DeprecatedClassMethods:
+ Exclude:
+ - 'lib/net/ssh/transport/packet_stream.rb'
+
+# Offense count: 10
+# Cop supports --auto-correct.
+Lint/DeprecatedOpenSSLConstant:
Exclude:
- - 'lib/net/ssh/authentication/session.rb'
- - 'lib/net/ssh/known_hosts.rb'
- 'lib/net/ssh/transport/openssl.rb'
- - 'test/integration/common.rb'
- - 'test/integration/test_forward.rb'
- - 'test/start/test_connection.rb'
+
+# Offense count: 2
+# Configuration parameters: AllowComments, AllowEmptyLambdas.
+Lint/EmptyBlock:
+ Exclude:
+ - 'test/common.rb'
- 'test/start/test_transport.rb'
+# Offense count: 1
+# Configuration parameters: AllowComments.
+Lint/EmptyWhen:
+ Exclude:
+ - 'lib/net/ssh/config.rb'
+
# Offense count: 72
Lint/ImplicitStringConcatenation:
Exclude:
- 'lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
-# Offense count: 1
-Lint/LiteralAsCondition:
+# Offense count: 4
+# Cop supports --auto-correct.
+Lint/IncompatibleIoSelectWithFiberScheduler:
Exclude:
- - 'lib/net/ssh/authentication/pageant.rb'
+ - 'lib/net/ssh/transport/packet_stream.rb'
+ - 'lib/net/ssh/transport/server_version.rb'
# Offense count: 2
+# Cop supports --auto-correct.
Lint/Loop:
Exclude:
- 'lib/net/ssh/authentication/methods/password.rb'
- 'lib/net/ssh/key_factory.rb'
# Offense count: 3
-# Configuration parameters: MaximumRangeSize.
-Lint/MissingCopEnableDirective:
+Lint/MissingSuper:
Exclude:
- - 'test/authentication/test_agent.rb'
- - 'test/authentication/test_certificate.rb'
- - 'test/integration/test_agent.rb'
+ - 'lib/net/ssh/proxy/jump.rb'
+ - 'test/common.rb'
+ - 'test/integration/mitm_server.rb'
# Offense count: 1
Lint/NonLocalExitFromIterator:
Exclude:
- 'lib/net/ssh/known_hosts.rb'
+# Offense count: 2
+# Cop supports --auto-correct.
+Lint/OrAssignmentToConstant:
+ Exclude:
+ - 'lib/net/ssh/authentication/pageant.rb'
+
+# Offense count: 6
+# Cop supports --auto-correct.
+# Configuration parameters: AllowedImplicitNamespaces.
+# AllowedImplicitNamespaces: Gem
+Lint/RaiseException:
+ Exclude:
+ - 'Rakefile'
+ - 'lib/net/ssh/buffer.rb'
+ - 'lib/net/ssh/key_factory.rb'
+
+# Offense count: 1
+# Cop supports --auto-correct.
+Lint/RedundantCopDisableDirective:
+ Exclude:
+ - 'lib/net/ssh/key_factory.rb'
+
# Offense count: 3
Lint/RescueException:
Exclude:
- 'lib/net/ssh/authentication/key_manager.rb'
- 'lib/net/ssh/service/forward.rb'
+# Offense count: 4
+# Cop supports --auto-correct.
+Lint/SendWithMixinArgument:
+ Exclude:
+ - 'lib/net/ssh/test/extensions.rb'
+
# Offense count: 2
Lint/ShadowedException:
Exclude:
- 'lib/net/ssh/authentication/key_manager.rb'
+# Offense count: 5
+# Configuration parameters: AllowComments, AllowNil.
+Lint/SuppressedException:
+ Exclude:
+ - 'lib/net/ssh/authentication/session.rb'
+ - 'lib/net/ssh/transport/openssl.rb'
+ - 'test/integration/common.rb'
+ - 'test/integration/test_forward.rb'
+
# Offense count: 1
# Configuration parameters: AllowKeywordBlockArguments.
Lint/UnderscorePrefixedVariableName:
Exclude:
- 'lib/net/ssh/test/local_packet.rb'
-# Offense count: 1
-# Cop supports --auto-correct.
-Lint/UnneededRequireStatement:
- Exclude:
- - 'lib/net/ssh/ruby_compat.rb'
-
-# Offense count: 60
+# Offense count: 15
# Cop supports --auto-correct.
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
Lint/UnusedBlockArgument:
@@ -221,21 +192,15 @@ Lint/UnusedBlockArgument:
- 'lib/net/ssh/connection/keepalive.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/service/forward.rb'
- - 'test/authentication/methods/test_password.rb'
- - 'test/authentication/test_agent.rb'
- - 'test/common.rb'
- - 'test/connection/test_channel.rb'
- - 'test/connection/test_session.rb'
- - 'test/transport/test_algorithms.rb'
- - 'test/transport/test_hmac.rb'
-# Offense count: 62
+# Offense count: 71
# Cop supports --auto-correct.
-# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
+# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods.
Lint/UnusedMethodArgument:
Enabled: false
# Offense count: 3
+# Cop supports --auto-correct.
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
Lint/UselessAccessModifier:
Exclude:
@@ -251,13 +216,20 @@ Lint/UselessAssignment:
- 'test/integration/common.rb'
- 'test/integration/test_forward.rb'
-# Offense count: 229
+# Offense count: 1
+# Cop supports --auto-correct.
+Lint/UselessTimes:
+ Exclude:
+ - 'test/integration/test_forward.rb'
+
+# Offense count: 202
+# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
Metrics/AbcSize:
- Max: 89
+ Max: 74
-# Offense count: 15
-# Configuration parameters: CountComments, ExcludedMethods.
-# ExcludedMethods: refine
+# Offense count: 16
+# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
+# IgnoredMethods: refine
Metrics/BlockLength:
Max: 59
@@ -266,37 +238,37 @@ Metrics/BlockLength:
Metrics/BlockNesting:
Max: 4
-# Offense count: 31
-# Configuration parameters: CountComments.
+# Offense count: 33
+# Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength:
Max: 488
-# Offense count: 38
+# Offense count: 37
+# Configuration parameters: IgnoredMethods.
Metrics/CyclomaticComplexity:
- Max: 27
- Exclude:
- - 'lib/net/ssh/config.rb'
+ Max: 32
-# Offense count: 211
-# Configuration parameters: CountComments, ExcludedMethods.
+# Offense count: 229
+# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
Metrics/MethodLength:
- Max: 82
+ Max: 72
-# Offense count: 2
-# Configuration parameters: CountComments.
+# Offense count: 3
+# Configuration parameters: CountComments, CountAsOne.
Metrics/ModuleLength:
Max: 160
-# Offense count: 1
-# Configuration parameters: CountKeywordArgs.
+# Offense count: 2
+# Configuration parameters: Max, CountKeywordArgs.
Metrics/ParameterLists:
- Max: 6
+ MaxOptionalParameters: 4
-# Offense count: 30
+# Offense count: 32
+# Configuration parameters: IgnoredMethods.
Metrics/PerceivedComplexity:
- Max: 20
+ Max: 32
-# Offense count: 9
+# Offense count: 10
Naming/AccessorMethodName:
Exclude:
- 'lib/net/ssh/authentication/methods/password.rb'
@@ -308,30 +280,17 @@ Naming/AccessorMethodName:
- 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb'
# Offense count: 2
+# Cop supports --auto-correct.
Naming/BinaryOperatorParameterName:
Exclude:
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/version.rb'
-# Offense count: 12
+# Offense count: 16
+# Configuration parameters: AllowedNames.
+# AllowedNames: module_parent
Naming/ClassAndModuleCamelCase:
- Exclude:
- - 'lib/net/ssh/transport/hmac/md5_96.rb'
- - 'lib/net/ssh/transport/hmac/sha1_96.rb'
- - 'lib/net/ssh/transport/hmac/sha2_256.rb'
- - 'lib/net/ssh/transport/hmac/sha2_256_96.rb'
- - 'lib/net/ssh/transport/hmac/sha2_256_etm.rb'
- - 'lib/net/ssh/transport/hmac/sha2_512.rb'
- - 'lib/net/ssh/transport/hmac/sha2_512_96.rb'
- - 'lib/net/ssh/transport/hmac/sha2_512_etm.rb'
- - 'test/transport/hmac/test_md5_96.rb'
- - 'test/transport/hmac/test_sha1_96.rb'
- - 'test/transport/hmac/test_sha2_256.rb'
- - 'test/transport/hmac/test_sha2_256_96.rb'
- - 'test/transport/hmac/test_sha2_256_etm.rb'
- - 'test/transport/hmac/test_sha2_512.rb'
- - 'test/transport/hmac/test_sha2_512_96.rb'
- - 'test/transport/hmac/test_sha2_512_etm.rb'
+ Enabled: false
# Offense count: 4
Naming/ConstantName:
@@ -340,9 +299,9 @@ Naming/ConstantName:
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
- 'lib/net/ssh/transport/openssl.rb'
-# Offense count: 11
-# Configuration parameters: Blacklist.
-# Blacklist: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))
+# Offense count: 12
+# Configuration parameters: ForbiddenDelimiters.
+# ForbiddenDelimiters: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))
Naming/HeredocDelimiterNaming:
Exclude:
- 'test/authentication/test_agent.rb'
@@ -352,7 +311,7 @@ Naming/HeredocDelimiterNaming:
- 'test/integration/test_agent.rb'
- 'test/test_key_factory.rb'
-# Offense count: 4
+# Offense count: 5
# Configuration parameters: EnforcedStyleForLeadingUnderscores.
# SupportedStylesForLeadingUnderscores: disallowed, required, optional
Naming/MemoizedInstanceVariableName:
@@ -361,7 +320,7 @@ Naming/MemoizedInstanceVariableName:
- 'test/authentication/test_key_manager.rb'
# Offense count: 32
-# Configuration parameters: EnforcedStyle.
+# Configuration parameters: EnforcedStyle, IgnoredPatterns.
# SupportedStyles: snake_case, camelCase
Naming/MethodName:
Exclude:
@@ -374,19 +333,10 @@ Naming/MethodName:
- 'test/test_config.rb'
- 'test/test_key_factory.rb'
-# Offense count: 4
-# Cop supports --auto-correct.
-# Configuration parameters: PreferredName.
-Naming/RescuedExceptionsVariableName:
- Exclude:
- - 'lib/net/ssh/connection/session.rb'
- - 'lib/net/ssh/service/forward.rb'
- - 'lib/net/ssh/verifiers/accept_new.rb'
-
# Offense count: 23
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
-# AllowedNames: io, id, to, by, on, in, at, ip, db
-Naming/UncommunicativeMethodParamName:
+# AllowedNames: at, by, db, id, in, io, ip, of, on, os, pp, to
+Naming/MethodParameterName:
Exclude:
- 'lib/net/ssh/authentication/certificate.rb'
- 'lib/net/ssh/authentication/ed25519.rb'
@@ -394,21 +344,56 @@ Naming/UncommunicativeMethodParamName:
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/buffered_io.rb'
- - 'lib/net/ssh/ruby_compat.rb'
- 'lib/net/ssh/test/socket.rb'
- 'lib/net/ssh/transport/ctr.rb'
- 'lib/net/ssh/transport/hmac/abstract.rb'
- 'lib/net/ssh/transport/identity_cipher.rb'
- 'test/connection/test_session.rb'
-# Offense count: 8
-# Configuration parameters: EnforcedStyle.
+# Offense count: 4
+# Cop supports --auto-correct.
+# Configuration parameters: PreferredName.
+Naming/RescuedExceptionsVariableName:
+ Exclude:
+ - 'lib/net/ssh/connection/session.rb'
+ - 'lib/net/ssh/service/forward.rb'
+ - 'lib/net/ssh/verifiers/accept_new.rb'
+
+# Offense count: 5
+# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers.
+# SupportedStyles: snake_case, normalcase, non_integer
+# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339
+Naming/VariableNumber:
+ Exclude:
+ - 'test/test_buffer.rb'
+ - 'test/test_known_hosts.rb'
+ - 'test/transport/test_identity_cipher.rb'
+
+# Offense count: 1
+# Cop supports --auto-correct.
+Security/IoMethods:
+ Exclude:
+ - 'lib/net/ssh/config.rb'
+
+# Offense count: 2
+# Configuration parameters: EnforcedStyle, AllowModifiersOnSymbols.
# SupportedStyles: inline, group
Style/AccessModifierDeclarations:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
- - 'lib/net/ssh/transport/openssl.rb'
- - 'test/test_key_factory.rb'
+
+# Offense count: 31
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle.
+# SupportedStyles: separated, grouped
+Style/AccessorGrouping:
+ Exclude:
+ - 'lib/net/ssh/authentication/certificate.rb'
+ - 'lib/net/ssh/transport/kex/abstract.rb'
+ - 'test/common.rb'
+ - 'test/connection/test_channel.rb'
+ - 'test/integration/mitm_server.rb'
+ - 'test/start/test_transport.rb'
# Offense count: 2
# Cop supports --auto-correct.
@@ -419,36 +404,19 @@ Style/Alias:
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/service/forward.rb'
-# Offense count: 31
+# Offense count: 9
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: always, conditionals
Style/AndOr:
Exclude:
- - 'lib/net/ssh/authentication/key_manager.rb'
- - 'lib/net/ssh/buffer.rb'
- - 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/connection/channel.rb'
- 'lib/net/ssh/connection/session.rb'
- - 'lib/net/ssh/key_factory.rb'
- 'lib/net/ssh/service/forward.rb'
- - 'lib/net/ssh/test/channel.rb'
- - 'lib/net/ssh/test/script.rb'
- - 'lib/net/ssh/transport/cipher_factory.rb'
- - 'lib/net/ssh/transport/hmac.rb'
- - 'lib/net/ssh/transport/key_expander.rb'
- - 'test/common.rb'
-
-# Offense count: 2
-# Configuration parameters: AllowedChars.
-Style/AsciiComments:
- Exclude:
- - 'lib/net/ssh/authentication/pageant.rb'
- - 'lib/net/ssh/buffered_io.rb'
-# Offense count: 8
+# Offense count: 9
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, IgnoredMethods, AllowBracesOnProceduralOneLiners.
+# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, IgnoredMethods, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
# FunctionalMethods: let, let!, subject, watch
@@ -463,53 +431,41 @@ Style/BlockDelimiters:
- 'lib/net/ssh/transport/ctr.rb'
- 'test/verifiers/test_always.rb'
-# Offense count: 7
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: braces, no_braces, context_dependent
-Style/BracesAroundHashParameters:
- Exclude:
- - 'lib/net/ssh/config.rb'
- - 'test/integration/test_ed25519_pkeys.rb'
- - 'test/integration/test_id_rsa_keys.rb'
- - 'test/transport/test_hmac.rb'
- - 'test/transport/test_session.rb'
-
# Offense count: 2
+# Cop supports --auto-correct.
+# Configuration parameters: AllowOnConstant.
Style/CaseEquality:
Exclude:
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/connection/session.rb'
+# Offense count: 2
+# Cop supports --auto-correct.
+Style/CaseLikeIf:
+ Exclude:
+ - 'lib/net/ssh/transport/openssl.rb'
+ - 'test/connection/test_session.rb'
+
# Offense count: 1
# Cop supports --auto-correct.
Style/CharacterLiteral:
Exclude:
- 'test/test_buffer.rb'
-# Offense count: 15
+# Offense count: 18
# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, EnforcedStyle.
+# Configuration parameters: EnforcedStyle.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
+ Enabled: false
+
+# Offense count: 1
+# Cop supports --auto-correct.
+# Configuration parameters: IgnoredMethods.
+# IgnoredMethods: ==, equal?, eql?
+Style/ClassEqualityComparison:
Exclude:
- - 'lib/net/ssh/transport/ctr.rb'
- - 'lib/net/ssh/transport/hmac.rb'
- - 'lib/net/ssh/transport/hmac/md5.rb'
- - 'lib/net/ssh/transport/hmac/md5_96.rb'
- - 'lib/net/ssh/transport/hmac/none.rb'
- - 'lib/net/ssh/transport/hmac/ripemd160.rb'
- - 'lib/net/ssh/transport/hmac/sha1.rb'
- - 'lib/net/ssh/transport/hmac/sha1_96.rb'
- - 'lib/net/ssh/transport/hmac/sha2_256.rb'
- - 'lib/net/ssh/transport/hmac/sha2_256_96.rb'
- - 'lib/net/ssh/transport/hmac/sha2_256_etm.rb'
- - 'lib/net/ssh/transport/hmac/sha2_512.rb'
- - 'lib/net/ssh/transport/hmac/sha2_512_96.rb'
- - 'lib/net/ssh/transport/hmac/sha2_512_etm.rb'
- - 'lib/net/ssh/transport/kex.rb'
- - 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb'
- - 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb'
+ - 'lib/net/ssh/service/forward.rb'
# Offense count: 7
Style/ClassVars:
@@ -525,10 +481,16 @@ Style/ColonMethodCall:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
+# Offense count: 2
+Style/CombinableLoops:
+ Exclude:
+ - 'lib/net/ssh/connection/channel.rb'
+ - 'test/integration/test_hmac_etm.rb'
+
# Offense count: 4
# Cop supports --auto-correct.
-# Configuration parameters: Keywords.
-# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW
+# Configuration parameters: Keywords, RequireColon.
+# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW, NOTE
Style/CommentAnnotation:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
@@ -537,6 +499,7 @@ Style/CommentAnnotation:
- 'lib/net/ssh/config.rb'
# Offense count: 3
+# Cop supports --auto-correct.
Style/CommentedKeyword:
Exclude:
- 'test/connection/test_session.rb'
@@ -554,13 +517,8 @@ Style/ConditionalAssignment:
- 'lib/net/ssh/transport/state.rb'
- 'test/test_key_factory.rb'
-# Offense count: 1
-# Cop supports --auto-correct.
-Style/DefWithParentheses:
- Exclude:
- - 'test/integration/test_forward.rb'
-
-# Offense count: 14
+# Offense count: 12
+# Configuration parameters: AllowedConstants.
Style/Documentation:
Exclude:
- 'spec/**/*'
@@ -568,7 +526,6 @@ Style/Documentation:
- 'lib/net/ssh/authentication/ed25519.rb'
- 'lib/net/ssh/connection/keepalive.rb'
- 'lib/net/ssh/connection/session.rb'
- - 'lib/net/ssh/ruby_compat.rb'
- 'lib/net/ssh/test/extensions.rb'
- 'lib/net/ssh/transport/kex.rb'
- 'lib/net/ssh/transport/key_expander.rb'
@@ -576,15 +533,19 @@ Style/Documentation:
# Offense count: 1
# Cop supports --auto-correct.
-Style/EmptyLiteral:
+Style/EvenOdd:
Exclude:
- - 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
+ - 'lib/net/ssh/buffer.rb'
-# Offense count: 1
+# Offense count: 9
# Cop supports --auto-correct.
-Style/EvenOdd:
+Style/ExplicitBlockArgument:
Exclude:
- - 'lib/net/ssh/buffer.rb'
+ - 'lib/net/ssh/loggable.rb'
+ - 'lib/net/ssh/test.rb'
+ - 'test/integration/common.rb'
+ - 'test/integration/mitm_server.rb'
+ - 'test/integration/test_forward.rb'
# Offense count: 2
# Cop supports --auto-correct.
@@ -595,32 +556,40 @@ Style/FormatString:
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/loggable.rb'
-# Offense count: 1
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: annotated, template, unannotated
-Style/FormatStringToken:
- Exclude:
- - 'lib/net/ssh/loggable.rb'
-
-# Offense count: 166
+# Offense count: 173
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
-# SupportedStyles: always, never
+# SupportedStyles: always, always_true, never
Style/FrozenStringLiteralComment:
Enabled: false
-# Offense count: 34
+# Offense count: 1
+# Cop supports --auto-correct.
+Style/GlobalStdStream:
+ Exclude:
+ - 'lib/net/ssh.rb'
+
+# Offense count: 35
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Enabled: false
+# Offense count: 3
+# Cop supports --auto-correct.
+# Configuration parameters: AllowSplatArgument.
+Style/HashConversion:
+ Exclude:
+ - 'lib/net/ssh/authentication/certificate.rb'
+ - 'test/test_config.rb'
+
# Offense count: 1
+# Cop supports --auto-correct.
# Configuration parameters: AllowIfModifier.
Style/IfInsideElse:
Exclude:
- 'lib/net/ssh/connection/session.rb'
-# Offense count: 16
+# Offense count: 13
# Cop supports --auto-correct.
Style/IfUnlessModifier:
Exclude:
@@ -629,8 +598,6 @@ Style/IfUnlessModifier:
- 'lib/net/ssh/proxy/command.rb'
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/transport/ctr.rb'
- - 'lib/net/ssh/transport/kex.rb'
- - 'lib/net/ssh/transport/kex/abstract5656.rb'
- 'lib/net/ssh/transport/key_expander.rb'
- 'test/integration/test_proxy.rb'
- 'test/test_key_factory.rb'
@@ -651,11 +618,6 @@ Style/LineEndConcatenation:
- 'lib/net/ssh/verifiers/always.rb'
# Offense count: 1
-Style/MethodMissingSuper:
- Exclude:
- - 'lib/net/ssh/connection/session.rb'
-
-# Offense count: 1
Style/MissingRespondToMissing:
Exclude:
- 'lib/net/ssh/connection/session.rb'
@@ -667,15 +629,16 @@ Style/MultilineIfThen:
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/service/forward.rb'
-# Offense count: 6
+# Offense count: 7
# Cop supports --auto-correct.
Style/MultilineWhenThen:
Exclude:
- - 'lib/net/ssh/test/packet.rb'
- 'lib/net/ssh/transport/packet_stream.rb'
- 'lib/net/ssh/transport/session.rb'
# Offense count: 5
+# Cop supports --auto-correct.
+# Configuration parameters: AllowMethodComparison.
Style/MultipleComparison:
Exclude:
- 'lib/net/ssh/authentication/agent.rb'
@@ -683,14 +646,14 @@ Style/MultipleComparison:
- 'lib/net/ssh/known_hosts.rb'
- 'lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb'
-# Offense count: 41
+# Offense count: 42
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: literals, strict
Style/MutableConstant:
Enabled: false
-# Offense count: 13
+# Offense count: 14
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: both, prefix, postfix
@@ -706,6 +669,13 @@ Style/NegatedIf:
- 'test/test_key_factory.rb'
- 'test/transport/test_state.rb'
+# Offense count: 2
+# Cop supports --auto-correct.
+Style/NegatedIfElseCondition:
+ Exclude:
+ - 'lib/net/ssh/transport/algorithms.rb'
+ - 'lib/net/ssh/transport/cipher_factory.rb'
+
# Offense count: 1
# Cop supports --auto-correct.
Style/NegatedWhile:
@@ -734,7 +704,7 @@ Style/Not:
Exclude:
- 'lib/net/ssh/connection/channel.rb'
-# Offense count: 8
+# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: Strict.
Style/NumericLiterals:
@@ -742,11 +712,27 @@ Style/NumericLiterals:
# Offense count: 29
# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
+# Configuration parameters: EnforcedStyle, IgnoredMethods.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Enabled: false
+# Offense count: 16
+# Configuration parameters: AllowedMethods.
+# AllowedMethods: respond_to_missing?
+Style/OptionalBooleanParameter:
+ Exclude:
+ - 'lib/net/ssh/connection/session.rb'
+ - 'lib/net/ssh/key_factory.rb'
+ - 'lib/net/ssh/prompt.rb'
+ - 'lib/net/ssh/test/channel.rb'
+ - 'lib/net/ssh/test/script.rb'
+ - 'lib/net/ssh/transport/algorithms.rb'
+ - 'lib/net/ssh/transport/session.rb'
+ - 'lib/net/ssh/transport/state.rb'
+ - 'test/common.rb'
+ - 'test/transport/test_server_version.rb'
+
# Offense count: 15
# Cop supports --auto-correct.
Style/ParallelAssignment:
@@ -771,7 +757,7 @@ Style/ParenthesesAroundCondition:
- 'lib/net/ssh/transport/ctr.rb'
- 'test/integration/test_proxy.rb'
-# Offense count: 33
+# Offense count: 23
# Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
@@ -779,7 +765,7 @@ Style/PercentLiteralDelimiters:
- 'net-ssh.gemspec'
- 'test/test_config.rb'
-# Offense count: 15
+# Offense count: 16
# Cop supports --auto-correct.
Style/PerlBackrefs:
Exclude:
@@ -805,33 +791,70 @@ Style/Proc:
# Offense count: 7
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
+# Configuration parameters: EnforcedStyle, AllowedCompactTypes.
# SupportedStyles: compact, exploded
Style/RaiseArgs:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
-# Offense count: 4
+# Offense count: 6
+# Cop supports --auto-correct.
+# Configuration parameters: Methods.
+Style/RedundantArgument:
+ Exclude:
+ - 'lib/net/ssh/known_hosts.rb'
+ - 'test/authentication/test_ed25519.rb'
+
+# Offense count: 5
# Cop supports --auto-correct.
Style/RedundantBegin:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
+ - 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/verifiers/accept_new.rb'
- 'test/manual/test_pageant.rb'
# Offense count: 1
# Cop supports --auto-correct.
-Style/RedundantParentheses:
+Style/RedundantCondition:
+ Exclude:
+ - 'lib/net/ssh/proxy/command.rb'
+
+# Offense count: 1
+# Cop supports --auto-correct.
+Style/RedundantFileExtensionInRequire:
+ Exclude:
+ - 'lib/net/ssh/transport/cipher_factory.rb'
+
+# Offense count: 2
+# Cop supports --auto-correct.
+Style/RedundantInterpolation:
+ Exclude:
+ - 'lib/net/ssh/proxy/socks5.rb'
+ - 'lib/net/ssh/transport/session.rb'
+
+# Offense count: 2
+# Cop supports --auto-correct.
+Style/RedundantPercentQ:
Exclude:
- - 'support/arcfour_check.rb'
+ - 'net-ssh.gemspec'
-# Offense count: 59
+# Offense count: 9
+# Cop supports --auto-correct.
+Style/RedundantRegexpEscape:
+ Exclude:
+ - 'lib/net/ssh/authentication/agent.rb'
+ - 'lib/net/ssh/buffer.rb'
+ - 'lib/net/ssh/config.rb'
+ - 'lib/net/ssh/transport/cipher_factory.rb'
+
+# Offense count: 86
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleReturnValues.
Style/RedundantReturn:
Enabled: false
-# Offense count: 14
+# Offense count: 18
# Cop supports --auto-correct.
Style/RedundantSelf:
Exclude:
@@ -848,8 +871,8 @@ Style/RescueModifier:
# Offense count: 25
# Cop supports --auto-correct.
-# Configuration parameters: ConvertCodeThatCanStartToReturnNil, Whitelist.
-# Whitelist: present?, blank?, presence, try, try!
+# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods.
+# AllowedMethods: present?, blank?, presence, try, try!
Style/SafeNavigation:
Exclude:
- 'lib/net/ssh/authentication/key_manager.rb'
@@ -865,6 +888,12 @@ Style/SafeNavigation:
- 'lib/net/ssh/transport/algorithms.rb'
- 'lib/net/ssh/transport/packet_stream.rb'
+# Offense count: 3
+# Cop supports --auto-correct.
+Style/SelectByRegexp:
+ Exclude:
+ - 'test/test_all.rb'
+
# Offense count: 2
# Cop supports --auto-correct.
Style/SelfAssignment:
@@ -896,9 +925,18 @@ Style/SingleLineMethods:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
+# Offense count: 3
+# Cop supports --auto-correct.
+# Configuration parameters: AllowModifier.
+Style/SoleNestedConditional:
+ Exclude:
+ - 'lib/net/ssh/transport/packet_stream.rb'
+ - 'test/common.rb'
+ - 'test/integration/test_proxy.rb'
+
# Offense count: 18
# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
+# Configuration parameters: RequireEnglish, EnforcedStyle.
# SupportedStyles: use_perl_names, use_english_names
Style/SpecialGlobalVars:
Exclude:
@@ -910,16 +948,39 @@ Style/SpecialGlobalVars:
- 'test/manual/test_pageant.rb'
- 'test/test_all.rb'
-# Offense count: 1754
+# Offense count: 1
+# Cop supports --auto-correct.
+Style/StringChars:
+ Exclude:
+ - 'test/transport/test_server_version.rb'
+
+# Offense count: 27
+# Cop supports --auto-correct.
+# Configuration parameters: Mode.
+Style/StringConcatenation:
+ Exclude:
+ - 'lib/net/ssh/authentication/certificate.rb'
+ - 'lib/net/ssh/authentication/key_manager.rb'
+ - 'lib/net/ssh/authentication/pageant.rb'
+ - 'lib/net/ssh/config.rb'
+ - 'lib/net/ssh/transport/algorithms.rb'
+ - 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
+ - 'test/authentication/test_key_manager.rb'
+ - 'test/integration/common.rb'
+ - 'test/integration/test_proxy.rb'
+ - 'test/test_buffer.rb'
+ - 'test/test_key_factory.rb'
+
+# Offense count: 1816
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiterals:
Enabled: false
-# Offense count: 11
+# Offense count: 6
# Cop supports --auto-correct.
-# Configuration parameters: IgnoredMethods.
+# Configuration parameters: AllowMethodsWithArguments, IgnoredMethods.
# IgnoredMethods: respond_to, define_method
Style/SymbolProc:
Exclude:
@@ -927,30 +988,17 @@ Style/SymbolProc:
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/test/extensions.rb'
- - 'lib/net/ssh/transport/algorithms.rb'
- - 'test/integration/test_forward.rb'
- - 'test/test/test_test.rb'
-
-# Offense count: 1
-# Cop supports --auto-correct.
-Style/UnneededCondition:
- Exclude:
- - 'lib/net/ssh/proxy/command.rb'
-
-# Offense count: 4
-# Cop supports --auto-correct.
-Style/UnneededInterpolation:
- Exclude:
- - 'lib/net/ssh/proxy/socks5.rb'
- - 'lib/net/ssh/transport/session.rb'
- - 'test/integration/test_forward.rb'
-# Offense count: 15
+# Offense count: 14
# Cop supports --auto-correct.
-Style/UnneededPercentQ:
+Style/UnpackFirst:
Exclude:
- - 'net-ssh.gemspec'
- - 'test/test_config.rb'
+ - 'lib/net/ssh/authentication/pageant.rb'
+ - 'lib/net/ssh/buffer.rb'
+ - 'lib/net/ssh/key_factory.rb'
+ - 'lib/net/ssh/known_hosts.rb'
+ - 'lib/net/ssh/transport/openssl.rb'
+ - 'lib/net/ssh/transport/packet_stream.rb'
# Offense count: 2
# Cop supports --auto-correct.
@@ -959,7 +1007,7 @@ Style/WhileUntilDo:
- 'lib/net/ssh/config.rb'
- 'test/integration/common.rb'
-# Offense count: 3
+# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: WordRegex.
# SupportedStyles: percent, brackets
@@ -973,10 +1021,3 @@ Style/ZeroLengthPredicate:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/connection/channel.rb'
-
-# Offense count: 1636
-# Cop supports --auto-correct.
-# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
-# URISchemes: http, https
-Metrics/LineLength:
- Max: 932
diff --git a/.travis.yml b/.travis.yml
index c314b65..2c2bdd3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,17 +1,16 @@
language: ruby
sudo: true
-dist: trusty
+dist: focal
addon:
hosts:
gateway.netssh
rvm:
- - 2.3.8
- - 2.4.8
- 2.5.7
- 2.6.5
- 2.7.0
+ - 3.0.0
- jruby-9.2.11.1
- rbx-3.107
- ruby-head
@@ -35,18 +34,18 @@ matrix:
install:
- export JRUBY_OPTS='--client -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -Xcext.enabled=false -J-Xss2m -Xcompile.invokedynamic=false'
- sudo pip install ansible urllib3 pyOpenSSL ndg-httpsclient pyasn1
- - gem install bundler -v "= 1.17"
+ - gem install bundler
- gem list bundler
- - bundle _1.17_ install
- - bundle _1.17_ -v
- - BUNDLE_GEMFILE=./Gemfile.noed25519 bundle _1.17_ install
+ - bundle install
+ - bundle -v
+ - BUNDLE_GEMFILE=./Gemfile.noed25519 bundle install
- sudo ansible-galaxy install rvm.ruby
- sudo chown -R travis:travis /home/travis/.ansible
- ansible-playbook ./test/integration/playbook.yml -i "localhost," --become -c local -e 'no_rvm=true' -e 'myuser=travis' -e 'mygroup=travis' -e 'homedir=/home/travis'
script:
- ssh -V
- - bundle _1.17_ exec rake test
- - BUNDLE_GEMFILE=./Gemfile.noed25519 bundle _1.17_ exec rake test
- - bundle _1.17_ exec rake test_test
- - bundle _1.17_ exec rubocop
+ - bundle exec rake test
+ - BUNDLE_GEMFILE=./Gemfile.noed25519 bundle exec rake test
+ - bundle exec rake test_test
+ - bundle exec rubocop
diff --git a/CHANGES.txt b/CHANGES.txt
index f973490..86c5bd1 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,19 @@
+=== 6.3.0 beta1
+
+ * Support cert based host key auth, fix asterisk in known_hosts [#833]
+ * Support kex dh-group14-sha256 [#795]
+ * Fix StrictHostKeyChecking ssh config parameter translation [#765]
+
+=== 6.2.0 rc1
+
+=== 6.2.0 beta1
+
+ * rsa-sha2-512, rsa-sha2-256 host_key algs [#771]
+ * JRuby aes*-ctr suppport [#767]
+
=== 6.1.0
- * adapt to ssh's default bahaviors when no username is provided.
+ * Adapt to ssh's default behaviors when no username is provided.
When Net::SSH.start user is nil and config has no entry
we default to Etc.getpwuid.name() instead of Etc.getlogin(). [#749]
@@ -36,7 +49,7 @@
=== 5.2.0.rc3
* Fix check_host_ip read from config
- * Support ssh-ed25519 in kown hosts
+ * Support ssh-ed25519 in known hosts
=== 5.2.0.rc2
@@ -59,7 +72,7 @@
=== 5.0.2
- * fix ctr for jruby [#612]
+ * Fix ctr for jruby [#612]
=== 5.0.1
diff --git a/Gemfile b/Gemfile
index 2bfe7d2..a328e11 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,3 +9,5 @@ if ENV["CI"]
gem 'codecov', require: false, group: :test
gem 'simplecov', require: false, group: :test
end
+
+gem 'webrick', group: %i[development test] if RUBY_VERSION.split(".")[0].to_i >= 3
diff --git a/Gemfile.noed25519 b/Gemfile.noed25519
index b6c3576..f13c7c3 100644
--- a/Gemfile.noed25519
+++ b/Gemfile.noed25519
@@ -8,3 +8,5 @@ if ENV["CI"] && !Gem.win_platform?
gem 'simplecov', require: false, group: :test
gem 'codecov', require: false, group: :test
end
+
+gem 'webrick', group: %i[development test] if RUBY_VERSION.split(".")[0].to_i >= 3
diff --git a/README.md b/README.md
index 50fbc48..42b82b1 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
[![Gem Version](https://badge.fury.io/rb/net-ssh.svg)](https://badge.fury.io/rb/net-ssh)
[![Join the chat at https://gitter.im/net-ssh/net-ssh](https://badges.gitter.im/net-ssh/net-ssh.svg)](https://gitter.im/net-ssh/net-ssh?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-[![Build Status](https://travis-ci.org/net-ssh/net-ssh.svg?branch=master)](https://travis-ci.org/net-ssh/net-ssh)
+[![Build status](https://github.com/net-ssh/net-ssh/actions/workflows/ci.yml/badge.svg)](https://github.com/net-ssh/net-ssh/actions/workflows/ci.yml)
[![Coverage status](https://codecov.io/gh/net-ssh/net-ssh/branch/master/graph/badge.svg)](https://codecov.io/gh/net-ssh/net-ssh)
[![Backers on Open Collective](https://opencollective.com/net-ssh/backers/badge.svg)](#backers])
[![Sponsors on Open Collective](https://opencollective.com/net-ssh/sponsors/badge.svg)](#sponsors)
# Net::SSH 6.x
-* Docs: http://net-ssh.github.com/net-ssh
+* Docs: http://net-ssh.github.io/net-ssh
* Issues: https://github.com/net-ssh/net-ssh/issues
* Codes: https://github.com/net-ssh/net-ssh
* Email: net-ssh@solutious.com
diff --git a/Rakefile b/Rakefile
index 0271797..92d7a9f 100644
--- a/Rakefile
+++ b/Rakefile
@@ -48,6 +48,7 @@ namespace :cert do
raw = File.read "net-ssh-public_cert.pem"
certificate = OpenSSL::X509::Certificate.new raw
raise Exception, "Not yet expired: #{certificate.not_after}" unless certificate.not_after < Time.now
+
sh "gem cert --build netssh@solutious.com --days 365*5 --private-key /mnt/gem/net-ssh-private_key.pem"
sh "mv gem-public_cert.pem net-ssh-public_cert.pem"
sh "gem cert --add net-ssh-public_cert.pem"
diff --git a/lib/net/ssh.rb b/lib/net/ssh.rb
index 292d6c6..b72ab7f 100644
--- a/lib/net/ssh.rb
+++ b/lib/net/ssh.rb
@@ -15,7 +15,6 @@ require 'net/ssh/connection/session'
require 'net/ssh/prompt'
module Net
-
# Net::SSH is a library for interacting, programmatically, with remote
# processes via the SSH2 protocol. Sessions are always initiated via
# Net::SSH.start. From there, a program interacts with the new SSH session
@@ -122,7 +121,7 @@ module Net
# * :forward_agent => set to true if you want the SSH agent connection to
# be forwarded
# * :known_hosts => a custom object holding known hosts records.
- # It must implement #search_for and add in a similiar manner as KnownHosts.
+ # It must implement #search_for and `add` in a similiar manner as KnownHosts.
# * :global_known_hosts_file => the location of the global known hosts
# file. Set to an array if you want to specify multiple global known
# hosts files. Defaults to %w(/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2).
@@ -215,7 +214,7 @@ module Net
# * :fingerprint_hash => 'MD5' or 'SHA256', defaults to 'SHA256'
# If +user+ parameter is nil it defaults to USER from ssh_config, or
# local username
- def self.start(host, user=nil, options={}, &block)
+ def self.start(host, user = nil, options = {}, &block)
invalid_options = options.keys - VALID_OPTIONS
if invalid_options.any?
raise ArgumentError, "invalid option(s): #{invalid_options.join(', ')}"
@@ -302,9 +301,9 @@ module Net
end
def self._sanitize_options(options)
- invalid_option_values = [nil,[nil]]
+ invalid_option_values = [nil, [nil]]
unless (options.values & invalid_option_values).empty?
- nil_options = options.select { |_k,v| invalid_option_values.include?(v) }.map(&:first)
+ nil_options = options.select { |_k, v| invalid_option_values.include?(v) }.map(&:first)
Kernel.warn "#{caller_locations(2, 1)[0]}: Passing nil, or [nil] to Net::SSH.start is deprecated for keys: #{nil_options.join(', ')}"
end
end
diff --git a/lib/net/ssh/authentication/agent.rb b/lib/net/ssh/authentication/agent.rb
index 15c75ea..a344626 100644
--- a/lib/net/ssh/authentication/agent.rb
+++ b/lib/net/ssh/authentication/agent.rb
@@ -13,6 +13,7 @@ module Net
module Authentication
# Class for representing agent-specific errors.
class AgentError < Net::SSH::Exception; end
+
# An exception for indicating that the SSH agent is not available.
class AgentNotAvailable < AgentError; end
@@ -39,6 +40,8 @@ module Net
SSH2_AGENT_ADD_IDENTITY = 17
SSH2_AGENT_REMOVE_IDENTITY = 18
SSH2_AGENT_REMOVE_ALL_IDENTITIES = 19
+ SSH2_AGENT_LOCK = 22
+ SSH2_AGENT_UNLOCK = 23
SSH2_AGENT_ADD_ID_CONSTRAINED = 25
SSH2_AGENT_FAILURE = 30
SSH2_AGENT_VERSION_RESPONSE = 103
@@ -62,7 +65,7 @@ module Net
# Instantiates a new agent object, connects to a running SSH agent,
# negotiates the agent protocol version, and returns the agent object.
- def self.connect(logger=nil, agent_socket_factory = nil, identity_agent = nil)
+ def self.connect(logger = nil, agent_socket_factory = nil, identity_agent = nil)
agent = new(logger)
agent.connect!(agent_socket_factory, identity_agent)
agent.negotiate!
@@ -71,7 +74,7 @@ module Net
# Creates a new Agent object, using the optional logger instance to
# report status.
- def initialize(logger=nil)
+ def initialize(logger = nil)
self.logger = logger
end
@@ -105,6 +108,7 @@ module Net
type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
raise AgentNotAvailable, "SSH2 agents are not yet supported" if type == SSH2_AGENT_VERSION_RESPONSE
+
if type == SSH2_AGENT_FAILURE
debug { "Unexpected response type==#{type}, this will be ignored" }
elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
@@ -173,7 +177,7 @@ module Net
req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED
type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key),
- :string, comment, :raw, constraints)
+ :string, comment, :raw, constraints)
raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS
end
@@ -189,6 +193,18 @@ module Net
raise AgentError, "could not remove all identity from agent" if type != SSH_AGENT_SUCCESS
end
+ # lock the ssh agent with password
+ def lock(password)
+ type, = send_and_wait(SSH2_AGENT_LOCK, :string, password)
+ raise AgentError, "could not lock agent" if type != SSH_AGENT_SUCCESS
+ end
+
+ # unlock the ssh agent with password
+ def unlock(password)
+ type, = send_and_wait(SSH2_AGENT_UNLOCK, :string, password)
+ raise AgentError, "could not unlock agent" if type != SSH_AGENT_SUCCESS
+ end
+
private
def unix_socket_class
@@ -235,31 +251,31 @@ module Net
case priv_key.ssh_type
when /^ssh-dss$/
Net::SSH::Buffer.from(:bignum, priv_key.p, :bignum, priv_key.q, :bignum, priv_key.g,
- :bignum, priv_key.pub_key, :bignum, priv_key.priv_key).to_s
+ :bignum, priv_key.pub_key, :bignum, priv_key.priv_key).to_s
when /^ssh-dss-cert-v01@openssh\.com$/
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.priv_key).to_s
when /^ecdsa\-sha2\-(\w*)$/
curve_name = OpenSSL::PKey::EC::CurveNameAliasInv[priv_key.group.curve_name]
Net::SSH::Buffer.from(:string, curve_name, :mstring, priv_key.public_key.to_bn.to_s(2),
- :bignum, priv_key.private_key).to_s
+ :bignum, priv_key.private_key).to_s
when /^ecdsa\-sha2\-(\w*)-cert-v01@openssh\.com$/
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.private_key).to_s
when /^ssh-ed25519$/
Net::SSH::Buffer.from(:string, priv_key.public_key.verify_key.to_bytes,
- :string, priv_key.sign_key.keypair).to_s
+ :string, priv_key.sign_key.keypair).to_s
when /^ssh-ed25519-cert-v01@openssh\.com$/
# Unlike the other certificate types, the public key is included after the certifiate.
Net::SSH::Buffer.from(:string, priv_key.to_blob,
- :string, priv_key.key.public_key.verify_key.to_bytes,
- :string, priv_key.key.sign_key.keypair).to_s
+ :string, priv_key.key.public_key.verify_key.to_bytes,
+ :string, priv_key.key.sign_key.keypair).to_s
when /^ssh-rsa$/
# `n` and `e` are reversed compared to the ordering in `OpenSSL::PKey::RSA#to_blob`.
Net::SSH::Buffer.from(:bignum, priv_key.n, :bignum, priv_key.e, :bignum, priv_key.d,
- :bignum, priv_key.iqmp, :bignum, priv_key.p, :bignum, priv_key.q).to_s
+ :bignum, priv_key.iqmp, :bignum, priv_key.p, :bignum, priv_key.q).to_s
when /^ssh-rsa-cert-v01@openssh\.com$/
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.d,
- :bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
- :bignum, priv_key.key.q).to_s
+ :bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
+ :bignum, priv_key.key.q).to_s
end
end
end
diff --git a/lib/net/ssh/authentication/certificate.rb b/lib/net/ssh/authentication/certificate.rb
index 82e37e9..5250789 100644
--- a/lib/net/ssh/authentication/certificate.rb
+++ b/lib/net/ssh/authentication/certificate.rb
@@ -31,12 +31,13 @@ module Net
cert.key_id = buffer.read_string
cert.valid_principals = buffer.read_buffer.read_all(&:read_string)
cert.valid_after = Time.at(buffer.read_int64)
-
+
cert.valid_before = if RUBY_PLATFORM == "java"
# 0x20c49ba5e353f7 = 0x7fffffffffffffff/1000, the largest value possible for JRuby
# JRuby Time.at multiplies the arg by 1000, and then stores it in a signed long.
- # 0x20c49ba5e353f7 = 292278994-08-17 01:12:55 -0600
- Time.at([0x20c49ba5e353f7, buffer.read_int64].min)
+ # 0x20c49ba2d52500 = 292278993-01-01 00:00:00 +0000
+ # JRuby 9.1 does not accept the year 292278994 because of edge cases (https://github.com/JodaOrg/joda-time/issues/190)
+ Time.at([0x20c49ba2d52500, buffer.read_int64].min)
else
Time.at(buffer.read_int64)
end
@@ -65,12 +66,12 @@ module Net
).to_s
end
- def ssh_do_sign(data)
- key.ssh_do_sign(data)
+ def ssh_do_sign(data, sig_alg = nil)
+ key.ssh_do_sign(data, sig_alg)
end
- def ssh_do_verify(sig, data)
- key.ssh_do_verify(sig, data)
+ def ssh_do_verify(sig, data, options = {})
+ key.ssh_do_verify(sig, data, options)
end
def to_pem
@@ -82,7 +83,7 @@ module Net
end
# Signs the certificate with key.
- def sign!(key, sign_nonce=nil)
+ def sign!(key, sign_nonce = nil)
# ssh-keygen uses 32 bytes of nonce.
self.nonce = sign_nonce || SecureRandom.random_bytes(32)
self.signature_key = key
@@ -93,7 +94,7 @@ module Net
self
end
- def sign(key, sign_nonce=nil)
+ def sign(key, sign_nonce = nil)
cert = clone
cert.sign!(key, sign_nonce)
end
@@ -124,6 +125,7 @@ module Net
def self.type_symbol(type)
types = { 1 => :user, 2 => :host }
raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
+
types.fetch(type)
end
private_class_method :type_symbol
@@ -133,6 +135,7 @@ module Net
def type_value(type)
types = { user: 1, host: 2 }
raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
+
types.fetch(type)
end
diff --git a/lib/net/ssh/authentication/constants.rb b/lib/net/ssh/authentication/constants.rb
index d0b88b0..8976aed 100644
--- a/lib/net/ssh/authentication/constants.rb
+++ b/lib/net/ssh/authentication/constants.rb
@@ -1,7 +1,6 @@
module Net
module SSH
module Authentication
-
# Describes the constants used by the Net::SSH::Authentication components
# of the Net::SSH library. Individual authentication method implemenations
# may define yet more constants that are specific to their implementation.
diff --git a/lib/net/ssh/authentication/ed25519.rb b/lib/net/ssh/authentication/ed25519.rb
index 0c5530c..dccc64f 100644
--- a/lib/net/ssh/authentication/ed25519.rb
+++ b/lib/net/ssh/authentication/ed25519.rb
@@ -14,7 +14,7 @@ module Net
module Authentication
module ED25519
class SigningKeyFromFile < SimpleDelegator
- def initialize(pk,sk)
+ def initialize(pk, sk)
key = ::Ed25519::SigningKey.from_keypair(sk)
raise ArgumentError, "pk does not match sk" unless pk == key.verify_key.to_bytes
@@ -44,9 +44,11 @@ module Net
datafull = datafull.strip
raise ArgumentError.new("Expected #{MBEGIN} at start of private key") unless datafull.start_with?(MBEGIN)
raise ArgumentError.new("Expected #{MEND} at end of private key") unless datafull.end_with?(MEND)
+
datab64 = datafull[MBEGIN.size...-MEND.size]
data = Base64.decode64(datab64)
raise ArgumentError.new("Expected #{MAGIC} at start of decoded private key") unless data.start_with?(MAGIC)
+
buffer = Net::SSH::Buffer.new(data[MAGIC.size + 1..-1])
ciphername = buffer.read_string
@@ -59,6 +61,7 @@ module Net
kdfopts = Net::SSH::Buffer.new(buffer.read_string)
num_keys = buffer.read_long
raise ArgumentError.new("Only 1 key is supported in ssh keys #{num_keys} was in private key") unless num_keys == 1
+
_pubkey = buffer.read_string
len = buffer.read_long
@@ -72,12 +75,13 @@ module Net
rounds = kdfopts.read_long
raise "BCryptPbkdf is not implemented for jruby" if RUBY_PLATFORM == "java"
+
key = BCryptPbkdf::key(password, salt, keylen + ivlen, rounds)
else
key = '\x00' * (keylen + ivlen)
end
- cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv:key[keylen...keylen + ivlen], decrypt: true)
+ cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv: key[keylen...keylen + ivlen], decrypt: true)
decoded = cipher.update(buffer.remainder_as_buffer.to_s)
decoded << cipher.final
@@ -112,7 +116,7 @@ module Net
end
def to_blob
- Net::SSH::Buffer.from(:mstring,"ssh-ed25519",:string,@verify_key.to_bytes).to_s
+ Net::SSH::Buffer.from(:mstring, "ssh-ed25519".dup, :string, @verify_key.to_bytes).to_s
end
def ssh_type
@@ -123,8 +127,8 @@ module Net
ssh_type
end
- def ssh_do_verify(sig,data)
- @verify_key.verify(sig,data)
+ def ssh_do_verify(sig, data, options = {})
+ @verify_key.verify(sig, data)
end
def to_pem
@@ -148,7 +152,7 @@ module Net
_comment = buffer.read_string
@pk = pk
- @sign_key = SigningKeyFromFile.new(pk,sk)
+ @sign_key = SigningKeyFromFile.new(pk, sk)
end
def to_blob
@@ -167,7 +171,7 @@ module Net
PubKey.new(@pk)
end
- def ssh_do_sign(data)
+ def ssh_do_sign(data, sig_alg = nil)
@sign_key.sign(data)
end
diff --git a/lib/net/ssh/authentication/ed25519_loader.rb b/lib/net/ssh/authentication/ed25519_loader.rb
index bcf920d..94f87aa 100644
--- a/lib/net/ssh/authentication/ed25519_loader.rb
+++ b/lib/net/ssh/authentication/ed25519_loader.rb
@@ -1,11 +1,9 @@
-module Net
- module SSH
+module Net
+ module SSH
module Authentication
-
# Loads ED25519 support which requires optinal dependecies like
# ed25519, bcrypt_pbkdf
module ED25519Loader
-
begin
require 'net/ssh/authentication/ed25519'
LOADED = true
@@ -14,20 +12,19 @@ module Net
ERROR = e
LOADED = false
end
-
+
def self.raiseUnlessLoaded(message)
description = ERROR.is_a?(LoadError) ? dependenciesRequiredForED25519 : ''
description << "#{ERROR.class} : \"#{ERROR.message}\"\n" if ERROR
raise NotImplementedError, "#{message}\n#{description}" unless LOADED
end
-
+
def self.dependenciesRequiredForED25519
result = "net-ssh requires the following gems for ed25519 support:\n"
result << " * ed25519 (>= 1.2, < 2.0)\n"
result << " * bcrypt_pbkdf (>= 1.0, < 2.0)\n" unless RUBY_PLATFORM == "java"
result << "See https://github.com/net-ssh/net-ssh/issues/565 for more information\n"
end
-
end
end
end
diff --git a/lib/net/ssh/authentication/key_manager.rb b/lib/net/ssh/authentication/key_manager.rb
index 242d5d5..563702c 100644
--- a/lib/net/ssh/authentication/key_manager.rb
+++ b/lib/net/ssh/authentication/key_manager.rb
@@ -6,7 +6,6 @@ require 'net/ssh/authentication/agent'
module Net
module SSH
module Authentication
-
# A trivial exception class used to report errors in the key manager.
class KeyManagerError < Net::SSH::Exception; end
@@ -42,7 +41,7 @@ module Net
# Create a new KeyManager. By default, the manager will
# use the ssh-agent if it is running and the `:use_agent` option
# is not false.
- def initialize(logger, options={})
+ def initialize(logger, options = {})
self.logger = logger
@key_files = []
@key_data = []
@@ -159,7 +158,7 @@ module Net
# Regardless of the identity's origin or who does the signing, this
# will always return the signature in an SSH2-specified "signature
# blob" format.
- def sign(identity, data)
+ def sign(identity, data, sig_alg = nil)
info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
if info[:key].nil? && info[:from] == :file
@@ -171,13 +170,27 @@ module Net
end
if info[:key]
- return Net::SSH::Buffer.from(:string, identity.ssh_signature_type,
- :mstring, info[:key].ssh_do_sign(data.to_s)).to_s
+ if sig_alg.nil?
+ signed = info[:key].ssh_do_sign(data.to_s)
+ sig_alg = identity.ssh_signature_type
+ else
+ signed = info[:key].ssh_do_sign(data.to_s, sig_alg)
+ end
+ return Net::SSH::Buffer.from(:string, sig_alg,
+ :mstring, signed).to_s
end
if info[:from] == :agent
raise KeyManagerError, "the agent is no longer available" unless agent
- return agent.sign(info[:identity], data.to_s)
+
+ case sig_alg
+ when "rsa-sha2-512"
+ return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_512)
+ when "rsa-sha2-256"
+ return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_256)
+ else
+ return agent.sign(info[:identity], data.to_s)
+ end
end
raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
@@ -201,6 +214,7 @@ module Net
# or if the agent is otherwise not available.
def agent
return unless use_agent?
+
@agent ||= Agent.connect(logger, options[:agent_socket_factory], options[:identity_agent])
rescue AgentNotAvailable
@use_agent = false
@@ -248,37 +262,35 @@ module Net
# Load prepared identities. Private key decryption errors ignored if ignore_decryption_errors
def load_identities(identities, ask_passphrase, ignore_decryption_errors)
identities.map do |identity|
- begin
- case identity[:load_from]
- when :pubkey_file
- key = KeyFactory.load_public_key(identity[:pubkey_file])
- { public_key: key, from: :file, file: identity[:privkey_file] }
- when :privkey_file
- private_key = KeyFactory.load_private_key(
- identity[:privkey_file], options[:passphrase], ask_passphrase, options[:password_prompt]
- )
- key = private_key.send(:public_key)
- { public_key: key, from: :file, file: identity[:privkey_file], key: private_key }
- when :data
- private_key = KeyFactory.load_data_private_key(
- identity[:data], options[:passphrase], ask_passphrase, "<key in memory>", options[:password_prompt]
- )
- key = private_key.send(:public_key)
- { public_key: key, from: :key_data, data: identity[:data], key: private_key }
- else
- identity
- end
- rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError, OpenSSL::PKey::PKeyError, ArgumentError => e
- if ignore_decryption_errors
- identity
- else
- process_identity_loading_error(identity, e)
- nil
- end
- rescue Exception => e
+ case identity[:load_from]
+ when :pubkey_file
+ key = KeyFactory.load_public_key(identity[:pubkey_file])
+ { public_key: key, from: :file, file: identity[:privkey_file] }
+ when :privkey_file
+ private_key = KeyFactory.load_private_key(
+ identity[:privkey_file], options[:passphrase], ask_passphrase, options[:password_prompt]
+ )
+ key = private_key.send(:public_key)
+ { public_key: key, from: :file, file: identity[:privkey_file], key: private_key }
+ when :data
+ private_key = KeyFactory.load_data_private_key(
+ identity[:data], options[:passphrase], ask_passphrase, "<key in memory>", options[:password_prompt]
+ )
+ key = private_key.send(:public_key)
+ { public_key: key, from: :key_data, data: identity[:data], key: private_key }
+ else
+ identity
+ end
+ rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError, OpenSSL::PKey::PKeyError, ArgumentError => e
+ if ignore_decryption_errors
+ identity
+ else
process_identity_loading_error(identity, e)
nil
end
+ rescue Exception => e
+ process_identity_loading_error(identity, e)
+ nil
end.compact
end
diff --git a/lib/net/ssh/authentication/methods/abstract.rb b/lib/net/ssh/authentication/methods/abstract.rb
index bcddd4f..f023011 100644
--- a/lib/net/ssh/authentication/methods/abstract.rb
+++ b/lib/net/ssh/authentication/methods/abstract.rb
@@ -7,7 +7,6 @@ module Net
module SSH
module Authentication
module Methods
-
# The base class of all user authentication methods. It provides a few
# bits of common functionality.
class Abstract
@@ -21,12 +20,22 @@ module Net
# this.
attr_reader :key_manager
+ # So far only affects algorithms used for rsa keys, but can be
+ # extended to other keys, e.g after reading of
+ # PubkeyAcceptedAlgorithms option from ssh_config file is implemented.
+ attr_reader :pubkey_algorithms
+
# Instantiates a new authentication method.
- def initialize(session, options={})
+ def initialize(session, options = {})
@session = session
@key_manager = options[:key_manager]
@options = options
@prompt = options[:password_prompt]
+ @pubkey_algorithms = options[:pubkey_algorithms] \
+ || %w[rsa-sha2-256-cert-v01@openssh.com
+ ssh-rsa-cert-v01@openssh.com
+ rsa-sha2-256
+ ssh-rsa]
self.logger = session.logger
end
@@ -47,7 +56,7 @@ module Net
# of the packet. The new packet is returned, ready for sending.
def userauth_request(username, next_service, auth_method, *others)
buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
- :string, username, :string, next_service, :string, auth_method)
+ :string, username, :string, next_service, :string, auth_method)
others.each do |value|
case value
diff --git a/lib/net/ssh/authentication/methods/hostbased.rb b/lib/net/ssh/authentication/methods/hostbased.rb
index a4afbb4..6c92ef4 100644
--- a/lib/net/ssh/authentication/methods/hostbased.rb
+++ b/lib/net/ssh/authentication/methods/hostbased.rb
@@ -4,19 +4,18 @@ module Net
module SSH
module Authentication
module Methods
-
# Implements the host-based SSH authentication method.
class Hostbased < Abstract
include Constants
# Attempts to perform host-based authorization of the user by trying
# all known keys.
- def authenticate(next_service, username, password=nil)
+ def authenticate(next_service, username, password = nil)
return false unless key_manager
key_manager.each_identity do |identity|
return true if authenticate_with(identity, next_service,
- username, key_manager)
+ username, key_manager)
end
return false
@@ -64,10 +63,9 @@ module Net
# Build the "core" hostbased request string.
def build_request(identity, next_service, username, hostname, client_username)
userauth_request(username, next_service, "hostbased", identity.ssh_type,
- Buffer.from(:key, identity).to_s, hostname, client_username).to_s
+ Buffer.from(:key, identity).to_s, hostname, client_username).to_s
end
end
-
end
end
end
diff --git a/lib/net/ssh/authentication/methods/keyboard_interactive.rb b/lib/net/ssh/authentication/methods/keyboard_interactive.rb
index 7652b21..db195d9 100644
--- a/lib/net/ssh/authentication/methods/keyboard_interactive.rb
+++ b/lib/net/ssh/authentication/methods/keyboard_interactive.rb
@@ -5,14 +5,13 @@ module Net
module SSH
module Authentication
module Methods
-
# Implements the "keyboard-interactive" SSH authentication method.
class KeyboardInteractive < Abstract
USERAUTH_INFO_REQUEST = 60
USERAUTH_INFO_RESPONSE = 61
# Attempt to authenticate the given user for the given service.
- def authenticate(next_service, username, password=nil)
+ def authenticate(next_service, username, password = nil)
debug { "trying keyboard-interactive" }
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
@@ -32,6 +31,7 @@ module Net
message[:authentications].split(/,/).include? 'keyboard-interactive'
return false unless interactive?
+
password = nil
debug { "retrying keyboard-interactive" }
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
diff --git a/lib/net/ssh/authentication/methods/none.rb b/lib/net/ssh/authentication/methods/none.rb
index d583b7d..d38e877 100644
--- a/lib/net/ssh/authentication/methods/none.rb
+++ b/lib/net/ssh/authentication/methods/none.rb
@@ -5,32 +5,29 @@ module Net
module SSH
module Authentication
module Methods
-
# Implements the "none" SSH authentication method.
class None < Abstract
# Attempt to authenticate as "none"
- def authenticate(next_service, user="", password="")
- send_message(userauth_request(user, next_service, "none"))
+ def authenticate(next_service, user = "", password = "")
+ send_message(userauth_request(user, next_service, "none"))
message = session.next_message
-
+
case message.type
when USERAUTH_SUCCESS
debug { "none succeeded" }
return true
when USERAUTH_FAILURE
debug { "none failed" }
-
+
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'none'
-
+
return false
else
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
- end
-
+ end
end
end
-
end
end
end
diff --git a/lib/net/ssh/authentication/methods/password.rb b/lib/net/ssh/authentication/methods/password.rb
index e18edee..ffb881c 100644
--- a/lib/net/ssh/authentication/methods/password.rb
+++ b/lib/net/ssh/authentication/methods/password.rb
@@ -6,12 +6,11 @@ module Net
module SSH
module Authentication
module Methods
-
# Implements the "password" SSH authentication method.
class Password < Abstract
# Attempt to authenticate the given user for the given service. If
# the password parameter is nil, this will ask for password
- def authenticate(next_service, username, password=nil)
+ def authenticate(next_service, username, password = nil)
clear_prompter!
retries = 0
max_retries = get_max_retries
@@ -29,6 +28,7 @@ module Net
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'password'
+
password = nil
end
end until (message.type != USERAUTH_FAILURE || retries >= max_retries)
@@ -74,7 +74,6 @@ module Net
options[:non_interactive] ? 0 : result
end
end
-
end
end
end
diff --git a/lib/net/ssh/authentication/methods/publickey.rb b/lib/net/ssh/authentication/methods/publickey.rb
index bff9ffd..48a56ab 100644
--- a/lib/net/ssh/authentication/methods/publickey.rb
+++ b/lib/net/ssh/authentication/methods/publickey.rb
@@ -6,14 +6,13 @@ module Net
module SSH
module Authentication
module Methods
-
# Implements the "publickey" SSH authentication method.
class Publickey < Abstract
# Attempts to perform public-key authentication for the given
# username, trying each identity known to the key manager. If any of
# them succeed, returns +true+, otherwise returns +false+. This
# requires the presence of a key manager.
- def authenticate(next_service, username, password=nil)
+ def authenticate(next_service, username, password = nil)
return false unless key_manager
key_manager.each_identity do |identity|
@@ -27,41 +26,40 @@ module Net
# Builds a packet that contains the request formatted for sending
# a public-key request to the server.
- def build_request(pub_key, username, next_service, has_sig)
+ def build_request(pub_key, username, next_service, alg, has_sig)
blob = Net::SSH::Buffer.new
blob.write_key pub_key
userauth_request(username, next_service, "publickey", has_sig,
- pub_key.ssh_type, blob.to_s)
+ alg, blob.to_s)
end
# Builds and sends a request formatted for a public-key
# authentication request.
- def send_request(pub_key, username, next_service, signature=nil)
- msg = build_request(pub_key, username, next_service, !signature.nil?)
+ def send_request(pub_key, username, next_service, alg, signature = nil)
+ msg = build_request(pub_key, username, next_service, alg,
+ !signature.nil?)
msg.write_string(signature) if signature
send_message(msg)
end
- # Attempts to perform public-key authentication for the given
- # username, with the given identity (public key). Returns +true+ if
- # successful, or +false+ otherwise.
- def authenticate_with(identity, next_service, username)
+ def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil)
debug { "trying publickey (#{identity.fingerprint})" }
- send_request(identity, username, next_service)
+ send_request(identity, username, next_service, alg)
message = session.next_message
case message.type
when USERAUTH_PK_OK
- buffer = build_request(identity, username, next_service, true)
+ buffer = build_request(identity, username, next_service, alg,
+ true)
sig_data = Net::SSH::Buffer.new
sig_data.write_string(session_id)
sig_data.append(buffer.to_s)
- sig_blob = key_manager.sign(identity, sig_data)
+ sig_blob = key_manager.sign(identity, sig_data, sig_alg)
- send_request(identity, username, next_service, sig_blob.to_s)
+ send_request(identity, username, next_service, alg, sig_blob.to_s)
message = session.next_message
case message.type
@@ -77,7 +75,7 @@ module Net
return false
else
raise Net::SSH::Exception,
- "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
+ "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
when USERAUTH_FAILURE
@@ -89,8 +87,50 @@ module Net
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
end
- end
+ # Attempts to perform public-key authentication for the given
+ # username, with the given identity (public key). Returns +true+ if
+ # successful, or +false+ otherwise.
+ def authenticate_with(identity, next_service, username)
+ type = identity.ssh_type
+ if type == "ssh-rsa"
+ pubkey_algorithms.each do |pk_alg|
+ case pk_alg
+ when "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa"
+ if authenticate_with_alg(identity, next_service, username, pk_alg, pk_alg)
+ # success
+ return true
+ end
+ end
+ end
+ elsif type == "ssh-rsa-cert-v01@openssh.com"
+ pubkey_algorithms.each do |pk_alg|
+ case pk_alg
+ when "rsa-sha2-512-cert-v01@openssh.com"
+ if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-512")
+ # success
+ return true
+ end
+ when "rsa-sha2-256-cert-v01@openssh.com"
+ if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-256")
+ # success
+ return true
+ end
+ when "ssh-rsa-cert-v01@openssh.com"
+ if authenticate_with_alg(identity, next_service, username, pk_alg)
+ # success
+ return true
+ end
+ end
+ end
+ elsif authenticate_with_alg(identity, next_service, username, type)
+ # success
+ return true
+ end
+ # failure
+ return false
+ end
+ end
end
end
end
diff --git a/lib/net/ssh/authentication/pageant.rb b/lib/net/ssh/authentication/pageant.rb
index a79802b..a186c17 100644
--- a/lib/net/ssh/authentication/pageant.rb
+++ b/lib/net/ssh/authentication/pageant.rb
@@ -21,10 +21,9 @@ end
require 'net/ssh/errors'
-module Net
- module SSH
+module Net
+ module SSH
module Authentication
-
# This module encapsulates the implementation of a socket factory that
# uses the PuTTY "pageant" utility to obtain information about SSH
# identities.
@@ -33,36 +32,35 @@ module Net
# by Guillaume Marçais (guillaume.marcais@free.fr). It is used and
# relicensed by permission.
module Pageant
-
# From Putty pageant.c
AGENT_MAX_MSGLEN = 8192
AGENT_COPYDATA_ID = 0x804e50ba
-
+
# The definition of the Windows methods and data structures used in
# communicating with the pageant process.
module Win # rubocop:disable Metrics/ModuleLength
# Compatibility on initialization
if RUBY_VERSION < "1.9"
extend DL::Importable
-
+
dlload 'user32.dll'
dlload 'kernel32.dll'
dlload 'advapi32.dll'
-
+
SIZEOF_DWORD = DL.sizeof('L')
elsif RUBY_VERSION < "2.1"
extend DL::Importer
- dlload 'user32.dll','kernel32.dll', 'advapi32.dll'
+ dlload 'user32.dll', 'kernel32.dll', 'advapi32.dll'
include DL::Win32Types
-
+
SIZEOF_DWORD = DL::SIZEOF_LONG
else
extend Fiddle::Importer
- dlload 'user32.dll','kernel32.dll', 'advapi32.dll'
+ dlload 'user32.dll', 'kernel32.dll', 'advapi32.dll'
include Fiddle::Win32Types
SIZEOF_DWORD = Fiddle::SIZEOF_LONG
end
-
+
if RUBY_ENGINE == "jruby"
typealias("HANDLE", "void *") # From winnt.h
typealias("PHANDLE", "void *") # From winnt.h
@@ -76,105 +74,105 @@ module Net
typealias("LPARAM", "long *") # From windef.h
typealias("PDWORD_PTR", "long *") # From basetsd.h
typealias("USHORT", "unsigned short") # From windef.h
-
+
# From winbase.h, winnt.h
INVALID_HANDLE_VALUE = -1
NULL = nil
PAGE_READWRITE = 0x0004
FILE_MAP_WRITE = 2
WM_COPYDATA = 74
-
+
SMTO_NORMAL = 0 # From winuser.h
-
+
SUFFIX = if RUBY_ENGINE == "jruby"
"A"
else
""
end
-
+
# args: lpClassName, lpWindowName
extern "HWND FindWindow#{SUFFIX}(LPCTSTR, LPCTSTR)"
-
+
# args: none
extern 'DWORD GetCurrentThreadId()'
-
+
# args: hFile, (ignored), flProtect, dwMaximumSizeHigh,
# dwMaximumSizeLow, lpName
extern "HANDLE CreateFileMapping#{SUFFIX}(HANDLE, void *, DWORD, " +
"DWORD, DWORD, LPCTSTR)"
-
+
# args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
# dwfileOffsetLow, dwNumberOfBytesToMap
extern 'LPVOID MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, DWORD)'
-
+
# args: lpBaseAddress
extern 'BOOL UnmapViewOfFile(LPCVOID)'
-
+
# args: hObject
extern 'BOOL CloseHandle(HANDLE)'
-
+
# args: hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult
extern "LRESULT SendMessageTimeout#{SUFFIX}(HWND, UINT, WPARAM, LPARAM, " +
"UINT, UINT, PDWORD_PTR)"
-
+
# args: none
extern 'DWORD GetLastError()'
-
+
# args: none
extern 'HANDLE GetCurrentProcess()'
-
+
# args: hProcessHandle, dwDesiredAccess, (out) phNewTokenHandle
extern 'BOOL OpenProcessToken(HANDLE, DWORD, PHANDLE)'
-
+
# args: hTokenHandle, uTokenInformationClass,
# (out) lpTokenInformation, dwTokenInformationLength
# (out) pdwInfoReturnLength
extern 'BOOL GetTokenInformation(HANDLE, UINT, LPVOID, DWORD, ' +
'PDWORD)'
-
+
# args: (out) lpSecurityDescriptor, dwRevisionLevel
extern 'BOOL InitializeSecurityDescriptor(LPVOID, DWORD)'
-
+
# args: (out) lpSecurityDescriptor, lpOwnerSid, bOwnerDefaulted
extern 'BOOL SetSecurityDescriptorOwner(LPVOID, LPVOID, BOOL)'
-
+
# args: pSecurityDescriptor
extern 'BOOL IsValidSecurityDescriptor(LPVOID)'
-
+
# Constants needed for security attribute retrieval.
# Specifies the access mask corresponding to the desired access
# rights.
TOKEN_QUERY = 0x8
-
+
# The value of TOKEN_USER from the TOKEN_INFORMATION_CLASS enum.
TOKEN_USER_INFORMATION_CLASS = 1
-
+
# The initial revision level assigned to the security descriptor.
REVISION = 1
-
+
# Structs for security attribute functions.
# Holds the retrieved user access token.
TOKEN_USER = struct ['void * SID', 'DWORD ATTRIBUTES']
-
+
# Contains the security descriptor, this gets passed to the
# function that constructs the shared memory map.
SECURITY_ATTRIBUTES = struct ['DWORD nLength',
'LPVOID lpSecurityDescriptor',
'BOOL bInheritHandle']
-
+
# The security descriptor holds security information.
SECURITY_DESCRIPTOR = struct ['UCHAR Revision', 'UCHAR Sbz1',
'USHORT Control', 'LPVOID Owner',
'LPVOID Group', 'LPVOID Sacl',
'LPVOID Dacl']
-
+
# The COPYDATASTRUCT is used to send WM_COPYDATA messages
COPYDATASTRUCT = if RUBY_ENGINE == "jruby"
struct ['ULONG_PTR dwData', 'DWORD cbData', 'LPVOID lpData']
else
struct ['uintptr_t dwData', 'DWORD cbData', 'LPVOID lpData']
end
-
+
# Compatibility for security attribute retrieval.
if RUBY_VERSION < "1.9"
# Alias functions to > 1.9 capitalization
@@ -196,15 +194,15 @@ module Net
alias_method new_name, name
module_function new_name
end
-
+
def self.malloc_ptr(size)
return DL.malloc(size)
end
-
+
def self.get_ptr(data)
return data.to_ptr
end
-
+
def self.set_ptr_data(ptr, data)
ptr[0] = data
end
@@ -220,15 +218,15 @@ module Net
attach_function :malloc, [:size_t], :pointer
attach_function :free, [:pointer], :void
end
-
+
def self.malloc_ptr(size)
Fiddle::Pointer.new(LibC.malloc(size), size, LibC.method(:free))
end
-
+
def self.get_ptr(ptr)
return data.address
end
-
+
def self.set_ptr_data(ptr, data)
ptr.write_string_length(data, data.size)
end
@@ -236,19 +234,19 @@ module Net
def self.malloc_ptr(size)
return DL::CPtr.malloc(size, DL::RUBY_FREE)
end
-
+
def self.get_ptr(data)
return DL::CPtr.to_ptr data
end
-
+
def self.set_ptr_data(ptr, data)
- DL::CPtr.new(ptr)[0,data.size] = data
+ DL::CPtr.new(ptr)[0, data.size] = data
end
end
-
+
def self.get_security_attributes_for_user
user = get_current_user
-
+
psd_information = malloc_ptr(Win::SECURITY_DESCRIPTOR.size)
raise_error_if_zero(
Win.InitializeSecurityDescriptor(psd_information,
@@ -261,45 +259,46 @@ module Net
raise_error_if_zero(
Win.IsValidSecurityDescriptor(psd_information)
)
-
+
sa = Win::SECURITY_ATTRIBUTES.new(to_struct_ptr(malloc_ptr(Win::SECURITY_ATTRIBUTES.size)))
sa.nLength = Win::SECURITY_ATTRIBUTES.size
sa.lpSecurityDescriptor = psd_information.to_i
sa.bInheritHandle = 1
-
+
return sa
end
-
+
if RUBY_ENGINE == "jruby"
def self.ptr_to_s(ptr, size)
ret = ptr.to_s(size)
ret << "\x00" while ret.size < size
ret
end
-
+
def self.ptr_to_handle(phandle)
phandle.ptr
end
-
+
def self.ptr_to_dword(ptr)
first = ptr.ptr.to_i
- second = ptr_to_s(ptr,Win::SIZEOF_DWORD).unpack('L')[0]
+ second = ptr_to_s(ptr, Win::SIZEOF_DWORD).unpack('L')[0]
raise "Error" unless first == second
+
first
end
-
+
def self.to_token_user(ptoken_information)
TOKEN_USER.new(ptoken_information.to_ptr)
end
-
+
def self.to_struct_ptr(ptr)
ptr.to_ptr
end
-
+
def self.get_sid(user)
- ptr_to_s(user.to_ptr.ptr,Win::SIZEOF_DWORD).unpack('L')[0]
+ ptr_to_s(user.to_ptr.ptr, Win::SIZEOF_DWORD).unpack('L')[0]
end
-
+
def self.get_sid_ptr(user)
user.to_ptr.ptr
end
@@ -307,39 +306,39 @@ module Net
def self.get_sid(user)
user.SID
end
-
+
def self.ptr_to_handle(phandle)
phandle.ptr.to_i
end
-
+
def self.to_struct_ptr(ptr)
ptr
end
-
+
def self.ptr_to_dword(ptr)
ptr.to_s(Win::SIZEOF_DWORD).unpack('L')[0]
end
-
+
def self.to_token_user(ptoken_information)
TOKEN_USER.new(ptoken_information)
end
-
+
def self.get_sid_ptr(user)
user.SID
end
end
-
+
def self.get_current_user
token_handle = open_process_token(Win.GetCurrentProcess,
Win::TOKEN_QUERY)
token_user = get_token_information(token_handle,
- Win::TOKEN_USER_INFORMATION_CLASS)
+ Win::TOKEN_USER_INFORMATION_CLASS)
return token_user
end
-
+
def self.open_process_token(process_handle, desired_access)
ptoken_handle = malloc_ptr(Win::SIZEOF_DWORD)
-
+
raise_error_if_zero(
Win.OpenProcessToken(process_handle, desired_access,
ptoken_handle)
@@ -347,12 +346,12 @@ module Net
token_handle = ptr_to_handle(ptoken_handle)
return token_handle
end
-
+
def self.get_token_information(token_handle,
token_information_class)
# Hold the size of the information to be returned
preturn_length = malloc_ptr(Win::SIZEOF_DWORD)
-
+
# Going to throw an INSUFFICIENT_BUFFER_ERROR, but that is ok
# here. This is retrieving the size of the information to be
# returned.
@@ -360,7 +359,7 @@ module Net
token_information_class,
Win::NULL, 0, preturn_length)
ptoken_information = malloc_ptr(ptr_to_dword(preturn_length))
-
+
# This call is going to write the requested information to
# the memory location referenced by token_information.
raise_error_if_zero(
@@ -370,74 +369,76 @@ module Net
ptoken_information.size,
preturn_length)
)
-
+
return to_token_user(ptoken_information)
end
-
+
def self.raise_error_if_zero(result)
if result == 0
raise "Windows error: #{Win.GetLastError}"
end
end
-
+
# Get a null-terminated string given a string.
def self.get_cstr(str)
return str + "\000"
end
end
-
+
# This is the pseudo-socket implementation that mimics the interface of
# a socket, translating each request into a Windows messaging call to
# the pageant daemon. This allows pageant support to be implemented
# simply by replacing the socket factory used by the Agent class.
class Socket
private_class_method :new
-
+
# The factory method for creating a new Socket instance.
def self.open
new
end
-
+
# Create a new instance that communicates with the running pageant
# instance. If no such instance is running, this will cause an error.
def initialize
@win = Win.FindWindow("Pageant", "Pageant")
-
+
if @win.to_i == 0
raise Net::SSH::Exception,
- "pageant process not running"
+ "pageant process not running"
end
-
+
@input_buffer = Net::SSH::Buffer.new
@output_buffer = Net::SSH::Buffer.new
end
-
+
# Forwards the data to #send_query, ignoring any arguments after
# the first.
def send(data, *args)
@input_buffer.append(data)
-
+
ret = data.length
-
+
while true
return ret if @input_buffer.length < 4
+
msg_length = @input_buffer.read_long + 4
@input_buffer.reset!
-
+
return ret if @input_buffer.length < msg_length
+
msg = @input_buffer.read!(msg_length)
@output_buffer.append(send_query(msg))
end
end
-
+
# Reads +n+ bytes from the cached result of the last query. If +n+
# is +nil+, returns all remaining data from the last query.
def read(n = nil)
@output_buffer.read(n)
end
-
+
def close; end
-
+
# Packages the given query string and sends it to the pageant
# process via the Windows messaging subsystem. The result is
# cached, to be returned piece-wise when #read is called.
@@ -446,29 +447,29 @@ module Net
filemap = 0
ptr = nil
id = Win.malloc_ptr(Win::SIZEOF_DWORD)
-
+
mapname = "PageantRequest%08x" % Win.GetCurrentThreadId()
security_attributes = Win.get_ptr Win.get_security_attributes_for_user
-
+
filemap = Win.CreateFileMapping(Win::INVALID_HANDLE_VALUE,
security_attributes,
Win::PAGE_READWRITE, 0,
AGENT_MAX_MSGLEN, mapname)
-
+
if filemap == 0 || filemap == Win::INVALID_HANDLE_VALUE
raise Net::SSH::Exception,
- "Creation of file mapping failed with error: #{Win.GetLastError}"
+ "Creation of file mapping failed with error: #{Win.GetLastError}"
end
-
+
ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
0)
-
+
if ptr.nil? || ptr.null?
raise Net::SSH::Exception, "Mapping of file failed"
end
-
+
Win.set_ptr_data(ptr, query)
-
+
# using struct to achieve proper alignment and field size on 64-bit platform
cds = Win::COPYDATASTRUCT.new(Win.malloc_ptr(Win::COPYDATASTRUCT.size))
cds.dwData = AGENT_COPYDATA_ID
@@ -476,14 +477,14 @@ module Net
cds.lpData = Win.get_cstr(mapname)
succ = Win.SendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL,
cds.to_ptr, Win::SMTO_NORMAL, 5000, id)
-
+
if succ > 0
retlen = 4 + ptr.to_s(4).unpack("N")[0]
res = ptr.to_s(retlen)
else
raise Net::SSH::Exception, "Message failed with error: #{Win.GetLastError}"
end
-
+
return res
ensure
Win.UnmapViewOfFile(ptr) unless ptr.nil? || ptr.null?
@@ -491,7 +492,6 @@ module Net
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/authentication/pub_key_fingerprint.rb b/lib/net/ssh/authentication/pub_key_fingerprint.rb
index a776006..42f2f16 100644
--- a/lib/net/ssh/authentication/pub_key_fingerprint.rb
+++ b/lib/net/ssh/authentication/pub_key_fingerprint.rb
@@ -22,12 +22,12 @@ module Net
# returned by OpenSSH's <tt>`ssh-add -l -E SHA256`</tt>, i.e.,
# trailing base64 padding '=' characters are stripped and the
# literal string +SHA256:+ is prepended.
- def fingerprint(algorithm='MD5')
+ def fingerprint(algorithm = 'MD5')
@fingerprint ||= {}
@fingerprint[algorithm] ||= PubKeyFingerprint.fingerprint(to_blob, algorithm)
end
- def self.fingerprint(blob, algorithm='MD5')
+ def self.fingerprint(blob, algorithm = 'MD5')
case algorithm.to_s.upcase
when 'MD5'
OpenSSL::Digest.hexdigest(algorithm, blob).scan(/../).join(":")
diff --git a/lib/net/ssh/authentication/session.rb b/lib/net/ssh/authentication/session.rb
index dfc5c06..773d704 100644
--- a/lib/net/ssh/authentication/session.rb
+++ b/lib/net/ssh/authentication/session.rb
@@ -11,7 +11,6 @@ require 'net/ssh/authentication/methods/keyboard_interactive'
module Net
module SSH
module Authentication
-
# Raised if the current authentication method is not allowed
class DisallowedMethod < Net::SSH::Exception
end
@@ -42,7 +41,7 @@ module Net
# Instantiates a new Authentication::Session object over the given
# transport layer abstraction.
- def initialize(transport, options={})
+ def initialize(transport, options = {})
self.logger = transport.logger
@transport = transport
@@ -55,7 +54,7 @@ module Net
# Attempts to authenticate the given user, in preparation for the next
# service request. Returns true if an authentication method succeeds in
# authenticating the user, and false otherwise.
- def authenticate(next_service, username, password=nil)
+ def authenticate(next_service, username, password = nil)
debug { "beginning authentication of `#{username}'" }
transport.send_message(transport.service_request("ssh-userauth"))
@@ -70,22 +69,23 @@ module Net
attempted = []
@auth_methods.each do |name|
+ next unless @allowed_auth_methods.include?(name)
+
+ attempted << name
+
+ debug { "trying #{name}" }
begin
- next unless @allowed_auth_methods.include?(name)
- attempted << name
-
- debug { "trying #{name}" }
- begin
- auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
- method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
- rescue NameError
- debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
- next
- end
-
- return true if method.authenticate(next_service, username, password)
- rescue Net::SSH::Authentication::DisallowedMethod
+ auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
+ method = auth_class.new(self,
+ key_manager: key_manager, password_prompt: options[:password_prompt],
+ pubkey_algorithms: options[:pubkey_algorithms] || nil)
+ rescue NameError
+ debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
+ next
end
+
+ return true if method.authenticate(next_service, username, password)
+ rescue Net::SSH::Authentication::DisallowedMethod
end
error { "all authorization methods failed (tried #{attempted.join(', ')})" }
@@ -129,6 +129,7 @@ module Net
def expect_message(type)
message = next_message
raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})" unless message.type == type
+
message
end
diff --git a/lib/net/ssh/buffer.rb b/lib/net/ssh/buffer.rb
index 0fe4e56..b68d656 100644
--- a/lib/net/ssh/buffer.rb
+++ b/lib/net/ssh/buffer.rb
@@ -5,7 +5,6 @@ require 'net/ssh/authentication/ed25519_loader'
module Net
module SSH
-
# Net::SSH::Buffer is a flexible class for building and parsing binary
# data packets. It provides a stream-like interface for sequentially
# reading data items from the buffer, as well as a useful helper method
@@ -71,7 +70,7 @@ module Net
# Creates a new buffer, initialized to the given content. The position
# is initialized to the beginning of the buffer.
- def initialize(content="")
+ def initialize(content = String.new)
@content = content.to_s
@position = 0
end
@@ -118,7 +117,7 @@ module Net
# Resets the buffer, making it empty. Also, resets the read position to
# 0.
def clear!
- @content = ""
+ @content = String.new
@position = 0
end
@@ -129,12 +128,12 @@ module Net
# would otherwise tend to grow without bound.
#
# Returns the buffer object itself.
- def consume!(n=position)
+ def consume!(n = position)
if n >= length
# optimize for a fairly common case
clear!
elsif n > 0
- @content = @content[n..-1] || ""
+ @content = @content[n..-1] || String.new
@position -= n
@position = 0 if @position < 0
end
@@ -172,7 +171,7 @@ module Net
# Reads and returns the next +count+ bytes from the buffer, starting from
# the read position. If +count+ is +nil+, this will return all remaining
# text in the buffer. This method will increment the pointer.
- def read(count=nil)
+ def read(count = nil)
count ||= length
count = length - @position if @position + count > length
@position += count
@@ -181,7 +180,7 @@ module Net
# Reads (as #read) and returns the given number of bytes from the buffer,
# and then consumes (as #consume!) all data up to the new read position.
- def read!(count=nil)
+ def read!(count = nil)
data = read(count)
consume!
data
@@ -237,6 +236,7 @@ module Net
def read_bignum
data = read_string
return unless data
+
OpenSSL::BN.new(data, 2)
end
@@ -346,7 +346,12 @@ module Net
# Optimized version of write where the caller gives up ownership of string
# to the method. This way we can mutate the string.
def write_moved(string)
- @content << string.force_encoding('BINARY')
+ @content <<
+ if string.frozen?
+ string.dup.force_encoding('BINARY')
+ else
+ string.force_encoding('BINARY')
+ end
self
end
diff --git a/lib/net/ssh/buffered_io.rb b/lib/net/ssh/buffered_io.rb
index 54a4889..c2d34e2 100644
--- a/lib/net/ssh/buffered_io.rb
+++ b/lib/net/ssh/buffered_io.rb
@@ -1,9 +1,8 @@
require 'net/ssh/buffer'
require 'net/ssh/loggable'
-module Net
+module Net
module SSH
-
# This module is used to extend sockets and other IO objects, to allow
# them to be buffered for both read and write. This abstraction makes it
# quite easy to write a select-based event loop
@@ -48,19 +47,19 @@ module Net
# end
module BufferedIo
include Loggable
-
+
# Called when the #extend is called on an object, with this module as the
# argument. It ensures that the modules instance variables are all properly
# initialized.
- def self.extended(object) #:nodoc:
+ def self.extended(object) # :nodoc:
# need to use __send__ because #send is overridden in Socket
object.__send__(:initialize_buffered_io)
end
-
+
# Tries to read up to +n+ bytes of data from the remote end, and appends
# the data to the input buffer. It returns the number of bytes read, or 0
# if no data was available to be read.
- def fill(n=8192)
+ def fill(n = 8192)
input.consume!
data = recv(n)
debug { "read #{data.length} bytes" }
@@ -70,31 +69,31 @@ module Net
@input_errors << e
return 0
end
-
+
# Read up to +length+ bytes from the input buffer. If +length+ is nil,
# all available data is read from the buffer. (See #available.)
- def read_available(length=nil)
+ def read_available(length = nil)
input.read(length || available)
end
-
+
# Returns the number of bytes available to be read from the input buffer.
# (See #read_available.)
def available
input.available
end
-
+
# Enqueues data in the output buffer, to be written when #send_pending
# is called. Note that the data is _not_ sent immediately by this method!
def enqueue(data)
output.append(data)
end
-
+
# Returns +true+ if there is data waiting in the output buffer, and
# +false+ otherwise.
def pending_write?
output.length > 0
end
-
+
# Sends as much of the pending output as possible. Returns +true+ if any
# data was sent, and +false+ otherwise.
def send_pending
@@ -107,7 +106,7 @@ module Net
return false
end
end
-
+
# Calls #send_pending repeatedly, if necessary, blocking until the output
# buffer is empty.
def wait_for_pending_sends
@@ -115,31 +114,32 @@ module Net
while output.length > 0
result = IO.select(nil, [self]) or next
next unless result[1].any?
+
send_pending
end
end
-
+
public # these methods are primarily for use in tests
-
- def write_buffer #:nodoc:
+
+ def write_buffer # :nodoc:
output.to_s
end
-
- def read_buffer #:nodoc:
+
+ def read_buffer # :nodoc:
input.to_s
end
-
+
private
-
+
#--
# Can't use attr_reader here (after +private+) without incurring the
# wrath of "ruby -w". We hates it.
#++
-
+
def input; @input; end
def output; @output; end
-
+
# Initializes the intput and output buffers for this object. This method
# is called automatically when the module is mixed into an object via
# Object#extend (see Net::SSH::BufferedIo.extended), but must be called
@@ -166,7 +166,7 @@ module Net
# http://github.com/net-ssh/net-ssh/tree/portfwfix
#
module ForwardedBufferedIo
- def fill(n=8192)
+ def fill(n = 8192)
begin
super(n)
rescue Errno::ECONNRESET => e
@@ -181,7 +181,7 @@ module Net
end
end
end
-
+
def send_pending
begin
super
@@ -198,6 +198,5 @@ module Net
end
end
end
-
end
end
diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb
index a40262e..86c75f5 100644
--- a/lib/net/ssh/config.rb
+++ b/lib/net/ssh/config.rb
@@ -1,6 +1,5 @@
module Net
module SSH
-
# The Net::SSH::Config class is used to parse OpenSSH configuration files,
# and translates that syntax into the configuration syntax that Net::SSH
# understands. This lets Net::SSH scripts read their configuration (to
@@ -34,7 +33,7 @@ module Net
# * ProxyJump => maps to the :proxy option
# * PubKeyAuthentication => maps to the :auth_methods option
# * RekeyLimit => :rekey_limit
- # * StrictHostKeyChecking => :strict_host_key_checking
+ # * StrictHostKeyChecking => :verify_host_key
# * User => :user
# * UserKnownHostsFile => :user_known_hosts_file
# * NumberOfPasswordPrompts => :number_of_password_prompts
@@ -66,7 +65,7 @@ module Net
# given +files+ (defaulting to the list of files returned by
# #default_files), translates the resulting hash into the options
# recognized by Net::SSH, and returns them.
- def for(host, files=expandable_default_files)
+ def for(host, files = expandable_default_files)
translate(files.inject({}) { |settings, file|
load(file, host, settings)
})
@@ -78,7 +77,7 @@ module Net
# ones. Returns a hash containing the OpenSSH options. (See
# #translate for how to convert the OpenSSH options into Net::SSH
# options.)
- def load(path, host, settings={}, base_dir = nil)
+ def load(path, host, settings = {}, base_dir = nil)
file = File.expand_path(path)
base_dir ||= File.dirname(file)
return settings unless File.readable?(file)
@@ -186,17 +185,35 @@ module Net
# Filters default_files down to the files that are expandable.
def expandable_default_files
default_files.keep_if do |path|
- begin
- File.expand_path(path)
- true
- rescue ArgumentError
- false
- end
+ File.expand_path(path)
+ true
+ rescue ArgumentError
+ false
end
end
private
+ def translate_verify_host_key(value)
+ case value
+ when false
+ :never
+ when true
+ :always
+ when 'accept-new'
+ :accept_new
+ end
+ end
+
+ def translate_keepalive(hash, value)
+ if value && value.to_i > 0
+ hash[:keepalive] = true
+ hash[:keepalive_interval] = value.to_i
+ else
+ hash[:keepalive] = false
+ end
+ end
+
TRANSLATE_CONFIG_KEY_RENAME_MAP = {
bindaddress: :bind_address,
compression: :compression,
@@ -211,13 +228,14 @@ module Net
identityfile: :keys,
fingerprinthash: :fingerprint_hash,
port: :port,
- stricthostkeychecking: :strict_host_key_checking,
user: :user,
userknownhostsfile: :user_known_hosts_file,
checkhostip: :check_host_ip
}.freeze
def translate_config_key(hash, key, value, settings)
case key
+ when :stricthostkeychecking
+ hash[:verify_host_key] = translate_verify_host_key(value)
when :ciphers
hash[:encryption] = value.split(/,/)
when :hostbasedauthentication
@@ -235,12 +253,7 @@ module Net
when :serveralivecountmax
hash[:keepalive_maxcount] = value.to_i if value
when :serveraliveinterval
- if value && value.to_i > 0
- hash[:keepalive] = true
- hash[:keepalive_interval] = value.to_i
- else
- hash[:keepalive] = false
- end
+ translate_keepalive(hash, value)
when :passwordauthentication
if value
(hash[:auth_methods] << 'password').uniq!
@@ -302,9 +315,9 @@ module Net
# host names.
def pattern2regex(pattern)
tail = pattern
- prefix = ""
+ prefix = String.new
while !tail.empty? do
- head,sep,tail = tail.partition(/[\*\?]/)
+ head, sep, tail = tail.partition(/[\*\?]/)
prefix = prefix + Regexp.quote(head)
case sep
when '*'
@@ -358,7 +371,7 @@ module Net
conditions = conditions.each_slice(2)
condition_matches = []
- conditions.each do |(kind,exprs)|
+ conditions.each do |(kind, exprs)|
exprs = unquote(exprs)
case kind.downcase
diff --git a/lib/net/ssh/connection/channel.rb b/lib/net/ssh/connection/channel.rb
index 7bfee72..6fcf790 100644
--- a/lib/net/ssh/connection/channel.rb
+++ b/lib/net/ssh/connection/channel.rb
@@ -5,7 +5,6 @@ require 'net/ssh/connection/term'
module Net
module SSH
module Connection
-
# The channel abstraction. Multiple "channels" can be multiplexed onto a
# single SSH channel, each operating independently and seemingly in parallel.
# This class represents a single such channel. Most operations performed
@@ -55,55 +54,55 @@ module Net
class Channel
include Loggable
include Constants
-
+
# The local id for this channel, assigned by the Net::SSH::Connection::Session instance.
attr_reader :local_id
-
+
# The remote id for this channel, assigned by the remote host.
attr_reader :remote_id
-
+
# The type of this channel, usually "session".
attr_reader :type
-
+
# The underlying Net::SSH::Connection::Session instance that supports this channel.
attr_reader :connection
-
+
# The maximum packet size that the local host can receive.
attr_reader :local_maximum_packet_size
-
+
# The maximum amount of data that the local end of this channel can
# receive. This is a total, not per-packet.
attr_reader :local_maximum_window_size
-
+
# The maximum packet size that the remote host can receive.
attr_reader :remote_maximum_packet_size
-
+
# The maximum amount of data that the remote end of this channel can
# receive. This is a total, not per-packet.
attr_reader :remote_maximum_window_size
-
+
# This is the remaining window size on the local end of this channel. When
# this reaches zero, no more data can be received.
attr_reader :local_window_size
-
+
# This is the remaining window size on the remote end of this channel. When
# this reaches zero, no more data can be sent.
attr_reader :remote_window_size
-
+
# A hash of properties for this channel. These can be used to store state
# information about this channel. See also #[] and #[]=.
attr_reader :properties
-
+
# The output buffer for this channel. Data written to the channel is
# enqueued here, to be written as CHANNEL_DATA packets during each pass of
# the event loop. See Connection::Session#process and #enqueue_pending_output.
- attr_reader :output #:nodoc:
-
+ attr_reader :output # :nodoc:
+
# The list of pending requests. Each time a request is sent which requires
# a reply, the corresponding callback is pushed onto this queue. As responses
# arrive, they are shifted off the front and handled.
- attr_reader :pending_requests #:nodoc:
-
+ attr_reader :pending_requests # :nodoc:
+
# Instantiates a new channel on the given connection, of the given type,
# and with the given id. If a block is given, it will be remembered until
# the channel is confirmed open by the server, and will be invoked at
@@ -112,36 +111,36 @@ module Net
# This also sets the default maximum packet size and maximum window size.
def initialize(connection, type, local_id, max_pkt_size = 0x8000, max_win_size = 0x20000, &on_confirm_open)
self.logger = connection.logger
-
+
@connection = connection
@type = type
@local_id = local_id
-
+
@local_maximum_packet_size = max_pkt_size
@local_window_size = @local_maximum_window_size = max_win_size
-
+
@on_confirm_open = on_confirm_open
-
+
@output = Buffer.new
-
+
@properties = {}
-
+
@pending_requests = []
@on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
@on_request = {}
@closing = @eof = @sent_eof = @local_closed = @remote_closed = false
end
-
+
# A shortcut for accessing properties of the channel (see #properties).
def [](name)
@properties[name]
end
-
+
# A shortcut for setting properties of the channel (see #properties).
def []=(name, value)
@properties[name] = value
end
-
+
# Syntactic sugar for executing a command. Sends a channel request asking
# that the given command be invoked. If the block is given, it will be
# called when the server responds. The first parameter will be the
@@ -161,7 +160,7 @@ module Net
def exec(command, &block)
send_channel_request("exec", :string, command, &block)
end
-
+
# Syntactic sugar for requesting that a subsystem be started. Subsystems
# are a way for other protocols (like SFTP) to be run, using SSH as
# the transport. Generally, you'll never need to call this directly unless
@@ -178,7 +177,7 @@ module Net
def subsystem(subsystem, &block)
send_channel_request("subsystem", :string, subsystem, &block)
end
-
+
# Syntactic sugar for setting an environment variable in the remote
# process' environment. Note that for security reasons, the server may
# refuse to set certain environment variables, or all, at the server's
@@ -190,7 +189,7 @@ module Net
def env(variable_name, variable_value, &block)
send_channel_request("env", :string, variable_name, :string, variable_value, &block)
end
-
+
# A hash of the valid PTY options (see #request_pty).
VALID_PTY_OPTIONS = { term: "xterm",
chars_wide: 80,
@@ -198,7 +197,7 @@ module Net
pixels_wide: 640,
pixels_high: 480,
modes: {} }
-
+
# Requests that a pseudo-tty (or "pty") be made available for this channel.
# This is useful when you want to invoke and interact with some kind of
# screen-based program (e.g., vim, or some menuing system).
@@ -218,24 +217,24 @@ module Net
# puts "could not obtain pty"
# end
# end
- def request_pty(opts={}, &block)
+ def request_pty(opts = {}, &block)
extra = opts.keys - VALID_PTY_OPTIONS.keys
raise ArgumentError, "invalid option(s) to request_pty: #{extra.inspect}" if extra.any?
-
+
opts = VALID_PTY_OPTIONS.merge(opts)
-
+
modes = opts[:modes].inject(Buffer.new) do |memo, (mode, data)|
memo.write_byte(mode).write_long(data)
end
# mark the end of the mode opcode list with a 0 byte
modes.write_byte(0)
-
+
send_channel_request("pty-req", :string, opts[:term],
- :long, opts[:chars_wide], :long, opts[:chars_high],
- :long, opts[:pixels_wide], :long, opts[:pixels_high],
- :string, modes.to_s, &block)
+ :long, opts[:chars_wide], :long, opts[:chars_high],
+ :long, opts[:pixels_wide], :long, opts[:pixels_high],
+ :string, modes.to_s, &block)
end
-
+
# Sends data to the channel's remote endpoint. This usually has the
# effect of sending the given string to the remote process' stdin stream.
# Note that it does not immediately send the data across the channel,
@@ -251,9 +250,10 @@ module Net
# channel.send_data("the password\n")
def send_data(data)
raise EOFError, "cannot send data if channel has declared eof" if eof?
+
output.append(data.to_s)
end
-
+
# Returns true if the channel exists in the channel list of the session,
# and false otherwise. This can be used to determine whether a channel has
# been closed or not.
@@ -262,7 +262,7 @@ module Net
def active?
connection.channels.key?(local_id)
end
-
+
# Runs the SSH event loop until the channel is no longer active. This is
# handy for blocking while you wait for some channel to finish.
#
@@ -271,7 +271,7 @@ module Net
def wait
connection.loop { active? }
end
-
+
# True if close() has been called; NOTE: if the channel has data waiting to
# be sent then the channel will close after all the data is sent. See
# closed?() to determine if we have actually sent CHANNEL_CLOSE to server.
@@ -280,61 +280,63 @@ module Net
def closing?
@closing
end
-
+
# True if we have sent CHANNEL_CLOSE to the remote server.
def local_closed?
@local_closed
end
-
+
def remote_closed?
@remote_closed
end
-
+
def remote_closed!
@remote_closed = true
end
-
+
# Requests that the channel be closed. It only marks the channel to be closed
# the CHANNEL_CLOSE message will be sent from event loop
def close
return if @closing
+
@closing = true
end
-
+
# Returns true if the local end of the channel has declared that no more
# data is forthcoming (see #eof!). Trying to send data via #send_data when
# this is true will result in an exception being raised.
def eof?
@eof
end
-
+
# Tells the remote end of the channel that no more data is forthcoming
# from this end of the channel. The remote end may still send data.
# The CHANNEL_EOF packet will be sent once the output buffer is empty.
def eof!
return if eof?
+
@eof = true
end
-
+
# If an #on_process handler has been set up, this will cause it to be
# invoked (passing the channel itself as an argument). It also causes all
# pending output to be enqueued as CHANNEL_DATA packets (see #enqueue_pending_output).
def process
@on_process.call(self) if @on_process
enqueue_pending_output
-
+
if @eof and not @sent_eof and output.empty? and remote_id and not @local_closed
connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id))
@sent_eof = true
end
-
+
if @closing and not @local_closed and output.empty? and remote_id
connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id))
@local_closed = true
connection.cleanup_channel(self)
end
end
-
+
# Registers a callback to be invoked when data packets are received by the
# channel. The callback is called with the channel as the first argument,
# and the data as the second.
@@ -349,7 +351,7 @@ module Net
old, @on_data = @on_data, block
old
end
-
+
# Registers a callback to be invoked when extended data packets are received
# by the channel. The callback is called with the channel as the first
# argument, the data type (as an integer) as the second, and the data as
@@ -364,7 +366,7 @@ module Net
old, @on_extended_data = @on_extended_data, block
old
end
-
+
# Registers a callback to be invoked for each pass of the event loop for
# this channel. There are no guarantees on timeliness in the event loop,
# but it will be called roughly once for each packet received by the
@@ -391,7 +393,7 @@ module Net
old, @on_process = @on_process, block
old
end
-
+
# Registers a callback to be invoked when the server acknowledges that a
# channel is closed. This is invoked with the channel as the sole argument.
#
@@ -402,7 +404,7 @@ module Net
old, @on_close = @on_close, block
old
end
-
+
# Registers a callback to be invoked when the server indicates that no more
# data will be sent to the channel (although the channel can still send
# data to the server). The channel is the sole argument to the callback.
@@ -414,7 +416,7 @@ module Net
old, @on_eof = @on_eof, block
old
end
-
+
# Registers a callback to be invoked when the server was unable to open
# the requested channel. The channel itself will be passed to the block,
# along with the integer "reason code" for the failure, and a textual
@@ -429,7 +431,7 @@ module Net
old, @on_open_failed = @on_open_failed, block
old
end
-
+
# Registers a callback to be invoked when a channel request of the given
# type is received. The callback will receive the channel as the first
# argument, and the associated (unparsed) data as the second. The data
@@ -460,7 +462,7 @@ module Net
old, @on_request[type] = @on_request[type], block
old
end
-
+
# Sends a new channel request with the given name. The extra +data+
# parameter must either be empty, or consist of an even number of
# arguments. See Net::SSH::Buffer.from for a description of their format.
@@ -486,28 +488,29 @@ module Net
def send_channel_request(request_name, *data, &callback)
info { "sending channel request #{request_name.inspect}" }
fail "Channel open not yet confirmed, please call send_channel_request(or exec) from block of open_channel" unless remote_id
+
msg = Buffer.from(:byte, CHANNEL_REQUEST,
- :long, remote_id, :string, request_name,
- :bool, !callback.nil?, *data)
+ :long, remote_id, :string, request_name,
+ :bool, !callback.nil?, *data)
connection.send_message(msg)
pending_requests << callback if callback
end
-
+
public # these methods are public, but for Net::SSH internal use only
-
+
# Enqueues pending output at the connection as CHANNEL_DATA packets. This
# does nothing if the channel has not yet been confirmed open (see
# #do_open_confirmation). This is called automatically by #process, which
# is called from the event loop (Connection::Session#process). You will
# generally not need to invoke it directly.
- def enqueue_pending_output #:nodoc:
+ def enqueue_pending_output # :nodoc:
return unless remote_id
-
+
while output.length > 0
length = output.length
length = remote_window_size if length > remote_window_size
length = remote_maximum_packet_size if length > remote_maximum_packet_size
-
+
if length > 0
connection.send_message(Buffer.from(:byte, CHANNEL_DATA, :long, remote_id, :string, output.read(length)))
output.consume!
@@ -517,14 +520,14 @@ module Net
end
end
end
-
+
# Invoked when the server confirms that a channel has been opened.
# The remote_id is the id of the channel as assigned by the remote host,
# and max_window and max_packet are the maximum window and maximum
# packet sizes, respectively. If an open-confirmation callback was
# given when the channel was created, it is invoked at this time with
# the channel itself as the sole argument.
- def do_open_confirmation(remote_id, max_window, max_packet) #:nodoc:
+ def do_open_confirmation(remote_id, max_window, max_packet) # :nodoc:
@remote_id = remote_id
@remote_window_size = @remote_maximum_window_size = max_window
@remote_maximum_packet_size = max_packet
@@ -533,7 +536,7 @@ module Net
set_remote_env(connection.options[:set_env]) if connection.options[:set_env]
@on_confirm_open.call(self) if @on_confirm_open
end
-
+
# Invoked when the server failed to open the channel. If an #on_open_failed
# callback was specified, it will be invoked with the channel, reason code,
# and description as arguments. Otherwise, a ChannelOpenFailed exception
@@ -545,16 +548,16 @@ module Net
raise ChannelOpenFailed.new(reason_code, description)
end
end
-
+
# Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and
# causes the remote window size to be adjusted upwards by the given
# number of bytes. This has the effect of allowing more data to be sent
# from the local end to the remote end of the channel.
- def do_window_adjust(bytes) #:nodoc:
+ def do_window_adjust(bytes) # :nodoc:
@remote_maximum_window_size += bytes
@remote_window_size += bytes
end
-
+
# Invoked when the server sends a channel request. If any #on_request
# callback has been registered for the specific type of this request,
# it is invoked. If +want_reply+ is true, a packet will be sent of
@@ -563,32 +566,32 @@ module Net
# CHANNEL_SUCCESS, unless the callback raised ChannelRequestFailed. The
# callback should accept the channel as the first argument, and the
# request-specific data as the second.
- def do_request(request, want_reply, data) #:nodoc:
+ def do_request(request, want_reply, data) # :nodoc:
result = true
-
+
begin
callback = @on_request[request] or raise ChannelRequestFailed
callback.call(self, data)
rescue ChannelRequestFailed
result = false
end
-
+
if want_reply
msg = Buffer.from(:byte, result ? CHANNEL_SUCCESS : CHANNEL_FAILURE, :long, remote_id)
connection.send_message(msg)
end
end
-
+
# Invokes the #on_data callback when the server sends data to the
# channel. This will reduce the available window size on the local end,
# but does not actually throttle requests that come in illegally when
# the window size is too small. The callback is invoked with the channel
# as the first argument, and the data as the second.
- def do_data(data) #:nodoc:
+ def do_data(data) # :nodoc:
update_local_window_size(data.length)
@on_data.call(self, data) if @on_data
end
-
+
# Invokes the #on_extended_data callback when the server sends
# extended data to the channel. This will reduce the available window
# size on the local end. The callback is invoked with the channel,
@@ -597,20 +600,20 @@ module Net
update_local_window_size(data.length)
@on_extended_data.call(self, type, data) if @on_extended_data
end
-
+
# Invokes the #on_eof callback when the server indicates that no
# further data is forthcoming. The callback is invoked with the channel
# as the argument.
def do_eof
@on_eof.call(self) if @on_eof
end
-
+
# Invokes the #on_close callback when the server closes a channel.
# The channel is the only argument.
def do_close
@on_close.call(self) if @on_close
end
-
+
# Invokes the next pending request callback with +false+ as the second
# argument.
def do_failure
@@ -620,7 +623,7 @@ module Net
error { "channel failure received with no pending request to handle it (bug?)" }
end
end
-
+
# Invokes the next pending request callback with +true+ as the second
# argument.
def do_success
@@ -683,10 +686,10 @@ module Net
#
# channel.set_remote_env foo: 'bar', baz: 'whale'
def set_remote_env(env)
+ env.each { |key, value| puts "E:#{key} V:#{value}" }
env.each { |key, value| self.env(key, value) }
end
end
-
end
end
end
diff --git a/lib/net/ssh/connection/constants.rb b/lib/net/ssh/connection/constants.rb
index a2b0257..5370fa8 100644
--- a/lib/net/ssh/connection/constants.rb
+++ b/lib/net/ssh/connection/constants.rb
@@ -1,11 +1,9 @@
module Net
module SSH
module Connection
-
# Definitions of constants that are specific to the connection layer of the
# SSH protocol.
module Constants
-
#--
# Connection protocol generic messages
#++
@@ -29,9 +27,7 @@ module Net
CHANNEL_REQUEST = 98
CHANNEL_SUCCESS = 99
CHANNEL_FAILURE = 100
-
end
-
end
end
end
diff --git a/lib/net/ssh/connection/event_loop.rb b/lib/net/ssh/connection/event_loop.rb
index cd9d3f1..5aac78c 100644
--- a/lib/net/ssh/connection/event_loop.rb
+++ b/lib/net/ssh/connection/event_loop.rb
@@ -1,7 +1,7 @@
require 'net/ssh/loggable'
-module Net
- module SSH
+module Net
+ module SSH
module Connection
# EventLoop can be shared across multiple sessions
#
@@ -11,81 +11,84 @@ module Net
# and we don't pass session.
class EventLoop
include Loggable
-
- def initialize(logger=nil)
+
+ def initialize(logger = nil)
self.logger = logger
@sessions = []
end
-
+
def register(session)
@sessions << session
end
-
+
# process until timeout
# if a block is given a session will be removed from loop
# if block returns false for that session
def process(wait = nil, &block)
return false unless ev_preprocess(&block)
-
+
ev_select_and_postprocess(wait)
end
-
+
# process the event loop but only for the sepcified session
def process_only(session, wait = nil)
orig_sessions = @sessions
begin
@sessions = [session]
return false unless ev_preprocess
+
ev_select_and_postprocess(wait)
ensure
@sessions = orig_sessions
end
end
-
+
# Call preprocess on each session. If block given and that
# block retuns false then we exit the processing
def ev_preprocess(&block)
return false if block_given? && !yield(self)
+
@sessions.each(&:ev_preprocess)
return false if block_given? && !yield(self)
+
return true
end
-
+
def ev_select_and_postprocess(wait)
owners = {}
r = []
w = []
minwait = nil
@sessions.each do |session|
- sr,sw,actwait = session.ev_do_calculate_rw_wait(wait)
+ sr, sw, actwait = session.ev_do_calculate_rw_wait(wait)
minwait = actwait if actwait && (minwait.nil? || actwait < minwait)
r.push(*sr)
w.push(*sw)
sr.each { |ri| owners[ri] = session }
sw.each { |wi| owners[wi] = session }
end
-
+
readers, writers, = IO.select(r, w, nil, minwait)
-
+
fired_sessions = {}
-
+
if readers
readers.each do |reader|
session = owners[reader]
- (fired_sessions[session] ||= { r: [],w: [] })[:r] << reader
+ (fired_sessions[session] ||= { r: [], w: [] })[:r] << reader
end
end
if writers
writers.each do |writer|
session = owners[writer]
- (fired_sessions[session] ||= { r: [],w: [] })[:w] << writer
+ (fired_sessions[session] ||= { r: [], w: [] })[:w] << writer
end
end
-
- fired_sessions.each do |s,rw|
- s.ev_do_handle_events(rw[:r],rw[:w])
+
+ fired_sessions.each do |s, rw|
+ s.ev_do_handle_events(rw[:r], rw[:w])
end
-
+
@sessions.each { |s| s.ev_do_postprocess(fired_sessions.key?(s)) }
true
end
@@ -97,18 +100,21 @@ module Net
# we call block with session as argument
def ev_preprocess(&block)
return false if block_given? && !yield(@sessions.first)
+
@sessions.each(&:ev_preprocess)
return false if block_given? && !yield(@sessions.first)
+
return true
end
-
+
def ev_select_and_postprocess(wait)
raise "Only one session expected" unless @sessions.count == 1
+
session = @sessions.first
- sr,sw,actwait = session.ev_do_calculate_rw_wait(wait)
+ sr, sw, actwait = session.ev_do_calculate_rw_wait(wait)
readers, writers, = IO.select(sr, sw, nil, actwait)
-
- session.ev_do_handle_events(readers,writers)
+
+ session.ev_do_handle_events(readers, writers)
session.ev_do_postprocess(!((readers.nil? || readers.empty?) && (writers.nil? || writers.empty?)))
end
end
diff --git a/lib/net/ssh/connection/keepalive.rb b/lib/net/ssh/connection/keepalive.rb
index fb9be05..cdbb3e0 100644
--- a/lib/net/ssh/connection/keepalive.rb
+++ b/lib/net/ssh/connection/keepalive.rb
@@ -1,45 +1,46 @@
require 'net/ssh/loggable'
-module Net
- module SSH
+module Net
+ module SSH
module Connection
-
class Keepalive
include Loggable
-
+
def initialize(session)
@last_keepalive_sent_at = nil
@unresponded_keepalive_count = 0
@session = session
self.logger = session.logger
end
-
+
def options
@session.options
end
-
+
def enabled?
options[:keepalive]
end
-
+
def interval
options[:keepalive_interval] || Session::DEFAULT_IO_SELECT_TIMEOUT
end
-
+
def should_send?
return false unless enabled?
return true unless @last_keepalive_sent_at
+
Time.now - @last_keepalive_sent_at >= interval
end
-
+
def keepalive_maxcount
(options[:keepalive_maxcount] || 3).to_i
end
-
+
def send_as_needed(was_events)
return if was_events
return unless should_send?
+
info { "sending keepalive #{@unresponded_keepalive_count}" }
-
+
@unresponded_keepalive_count += 1
@session.send_global_request("keepalive@openssh.com") { |success, response|
debug { "keepalive response successful. Missed #{@unresponded_keepalive_count - 1} keepalives" }
@@ -53,7 +54,6 @@ module Net
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/connection/session.rb b/lib/net/ssh/connection/session.rb
index 61abd76..fbfc017 100644
--- a/lib/net/ssh/connection/session.rb
+++ b/lib/net/ssh/connection/session.rb
@@ -5,10 +5,9 @@ require 'net/ssh/service/forward'
require 'net/ssh/connection/keepalive'
require 'net/ssh/connection/event_loop'
-module Net
- module SSH
+module Net
+ module SSH
module Connection
-
# A session class representing the connection service running on top of
# the SSH transport layer. It manages the creation of channels (see
# #open_channel), and the dispatching of messages to the various channels.
@@ -28,50 +27,50 @@ module Net
class Session
include Loggable
include Constants
-
+
# Default IO.select timeout threshold
DEFAULT_IO_SELECT_TIMEOUT = 300
-
+
# The underlying transport layer abstraction (see Net::SSH::Transport::Session).
attr_reader :transport
-
+
# The map of options that were used to initialize this instance.
attr_reader :options
-
+
# The collection of custom properties for this instance. (See #[] and #[]=).
attr_reader :properties
-
+
# The map of channels, each key being the local-id for the channel.
- attr_reader :channels #:nodoc:
-
+ attr_reader :channels # :nodoc:
+
# The map of listeners that the event loop knows about. See #listen_to.
- attr_reader :listeners #:nodoc:
-
+ attr_reader :listeners # :nodoc:
+
# The map of specialized handlers for opening specific channel types. See
# #on_open_channel.
- attr_reader :channel_open_handlers #:nodoc:
-
+ attr_reader :channel_open_handlers # :nodoc:
+
# The list of callbacks for pending requests. See #send_global_request.
- attr_reader :pending_requests #:nodoc:
-
+ attr_reader :pending_requests # :nodoc:
+
class NilChannel
def initialize(session)
@session = session
end
-
+
def method_missing(sym, *args)
@session.lwarn { "ignoring request #{sym.inspect} for non-existent (closed?) channel; probably ssh server bug" }
end
end
-
+
# Create a new connection service instance atop the given transport
# layer. Initializes the listeners to be only the underlying socket object.
- def initialize(transport, options={})
+ def initialize(transport, options = {})
self.logger = transport.logger
-
+
@transport = transport
@options = options
-
+
@channel_id_counter = -1
@channels = Hash.new(NilChannel.new(self))
@listeners = { transport.socket => nil }
@@ -79,34 +78,34 @@ module Net
@channel_open_handlers = {}
@on_global_request = {}
@properties = (options[:properties] || {}).dup
-
+
@max_pkt_size = (options.key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000)
@max_win_size = (options.key?(:max_win_size) ? options[:max_win_size] : 0x20000)
-
+
@keepalive = Keepalive.new(self)
-
+
@event_loop = options[:event_loop] || SingleSessionEventLoop.new
@event_loop.register(self)
end
-
+
# Retrieves a custom property from this instance. This can be used to
# store additional state in applications that must manage multiple
# SSH connections.
def [](key)
@properties[key]
end
-
+
# Sets a custom property for this instance.
def []=(key, value)
@properties[key] = value
end
-
+
# Returns the name of the host that was given to the transport layer to
# connect to.
def host
transport.host
end
-
+
# Returns true if the underlying transport has been closed. Note that
# this can be a little misleading, since if the remote server has
# closed the connection, the local end will still think it is open
@@ -115,7 +114,7 @@ module Net
def closed?
transport.closed?
end
-
+
# Closes the session gracefully, blocking until all channels have
# successfully closed, and then closes the underlying transport layer
# connection.
@@ -129,7 +128,7 @@ module Net
end
transport.close
end
-
+
# Performs a "hard" shutdown of the connection. In general, this should
# never be done, but it might be necessary (in a rescue clause, for instance,
# when the connection needs to close but you don't know the status of the
@@ -137,10 +136,10 @@ module Net
def shutdown!
transport.shutdown!
end
-
+
# preserve a reference to Kernel#loop
alias :loop_forever :loop
-
+
# Returns +true+ if there are any channels currently active on this
# session. By default, this will not include "invisible" channels
# (such as those created by forwarding ports and such), but if you pass
@@ -150,14 +149,14 @@ module Net
# to be run.
#
# ssh.loop { ssh.busy? }
- def busy?(include_invisible=false)
+ def busy?(include_invisible = false)
if include_invisible
channels.any?
else
channels.any? { |id, ch| !ch[:invisible] }
end
end
-
+
# The main event loop. Calls #process until #process returns false. If a
# block is given, it is passed to #process, otherwise a default proc is
# used that just returns true if there are any channels active (see #busy?).
@@ -175,7 +174,7 @@ module Net
# int_pressed = false
# trap("INT") { int_pressed = true }
# ssh.loop(0.1) { not int_pressed }
- def loop(wait=nil, &block)
+ def loop(wait = nil, &block)
running = block || Proc.new { busy? }
loop_forever { break unless process(wait, &running) }
begin
@@ -188,7 +187,7 @@ module Net
end
end
end
-
+
# The core of the event loop. It processes a single iteration of the event
# loop. If a block is given, it should return false when the processing
# should abort, which causes #process to return false. Otherwise,
@@ -223,13 +222,13 @@ module Net
# connections.delete_if { |ssh| !ssh.process(0.1, &condition) }
# break if connections.empty?
# end
- def process(wait=nil, &block)
+ def process(wait = nil, &block)
@event_loop.process(wait, &block)
rescue StandardError
force_channel_cleanup_on_close if closed?
raise
end
-
+
# This is called internally as part of #process. It dispatches any
# available incoming packets, and then runs Net::SSH::Connection::Channel#process
# for any active channels. If a block is given, it is invoked at the
@@ -237,31 +236,33 @@ module Net
# false, this method returns false. Otherwise, it returns true.
def preprocess(&block)
return false if block_given? && !yield(self)
+
ev_preprocess(&block)
return false if block_given? && !yield(self)
+
return true
end
-
+
# Called by event loop to process available data before going to
# event multiplexing
def ev_preprocess(&block)
dispatch_incoming_packets(raise_disconnect_errors: false)
each_channel { |id, channel| channel.process unless channel.local_closed? }
end
-
+
# Returns the file descriptors the event loop should wait for read/write events,
# we also return the max wait
def ev_do_calculate_rw_wait(wait)
r = listeners.keys
w = r.select { |w2| w2.respond_to?(:pending_write?) && w2.pending_write? }
- [r,w,io_select_wait(wait)]
+ [r, w, io_select_wait(wait)]
end
-
+
# This is called internally as part of #process.
def postprocess(readers, writers)
ev_do_handle_events(readers, writers)
end
-
+
# It loops over the given arrays of reader IO's and writer IO's,
# processing them as needed, and
# then calls Net::SSH::Transport::Session#rekey_as_needed to allow the
@@ -277,12 +278,12 @@ module Net
end
end
end
-
+
Array(writers).each do |writer|
writer.send_pending
end
end
-
+
# calls Net::SSH::Transport::Session#rekey_as_needed to allow the
# transport layer to rekey
def ev_do_postprocess(was_events)
@@ -290,7 +291,7 @@ module Net
transport.rekey_as_needed
true
end
-
+
# Send a global request of the given type. The +extra+ parameters must
# be even in number, and conform to the same format as described for
# Net::SSH::Buffer.from. If a callback is not specified, the request will
@@ -314,7 +315,7 @@ module Net
pending_requests << callback if callback
self
end
-
+
# Requests that a new channel be opened. By default, the channel will be
# of type "session", but if you know what you're doing you can select any
# of the channel types supported by the SSH protocol. The +extra+ parameters
@@ -334,27 +335,27 @@ module Net
# end
#
# channel.wait
- def open_channel(type="session", *extra, &on_confirm)
+ def open_channel(type = "session", *extra, &on_confirm)
local_id = get_next_channel_id
-
+
channel = Channel.new(self, type, local_id, @max_pkt_size, @max_win_size, &on_confirm)
msg = Buffer.from(:byte, CHANNEL_OPEN, :string, type, :long, local_id,
- :long, channel.local_maximum_window_size,
- :long, channel.local_maximum_packet_size, *extra)
+ :long, channel.local_maximum_window_size,
+ :long, channel.local_maximum_packet_size, *extra)
send_message(msg)
-
+
channels[local_id] = channel
end
-
+
class StringWithExitstatus < String
def initialize(str, exitstatus)
super(str)
@exitstatus = exitstatus
end
-
+
attr_reader :exitstatus
end
-
+
# A convenience method for executing a command and interacting with it. If
# no block is given, all output is printed via $stdout and $stderr. Otherwise,
# the block is called for each data and extended data packet, with three
@@ -379,17 +380,17 @@ module Net
open_channel do |channel|
channel.exec(command) do |ch, success|
raise "could not execute command: #{command.inspect}" unless success
-
+
if status
- channel.on_request("exit-status") do |ch2,data|
+ channel.on_request("exit-status") do |ch2, data|
status[:exit_code] = data.read_long
end
-
+
channel.on_request("exit-signal") do |ch2, data|
status[:exit_signal] = data.read_long
end
end
-
+
channel.on_data do |ch2, data|
if block
block.call(ch2, :stdout, data)
@@ -397,7 +398,7 @@ module Net
$stdout.print(data)
end
end
-
+
channel.on_extended_data do |ch2, type, data|
if block
block.call(ch2, :stderr, data)
@@ -408,7 +409,7 @@ module Net
end
end
end
-
+
# Same as #exec, except this will block until the command finishes. Also,
# if no block is given, this will return all output (stdout and stderr)
# as a single string.
@@ -418,20 +419,20 @@ module Net
# the returned string has an exitstatus method to query it's exit satus
def exec!(command, status: nil, &block)
block_or_concat = block || Proc.new do |ch, type, data|
- ch[:result] ||= ""
+ ch[:result] ||= String.new
ch[:result] << data
end
-
+
status ||= {}
channel = exec(command, status: status, &block_or_concat)
channel.wait
-
- channel[:result] ||= "" unless block
+
+ channel[:result] ||= String.new unless block
channel[:result] &&= channel[:result].force_encoding("UTF-8") unless block
-
+
StringWithExitstatus.new(channel[:result], status[:exit_code]) if channel[:result]
end
-
+
# Enqueues a message to be sent to the server as soon as the socket is
# available for writing. Most programs will never need to call this, but
# if you are implementing an extension to the SSH protocol, or if you
@@ -442,7 +443,7 @@ module Net
def send_message(message)
transport.enqueue_message(message)
end
-
+
# Adds an IO object for the event loop to listen to. If a callback
# is given, it will be invoked when the io is ready to be read, otherwise,
# the io will merely have its #fill method invoked.
@@ -480,19 +481,19 @@ module Net
def listen_to(io, &callback)
listeners[io] = callback
end
-
+
# Removes the given io object from the listeners collection, so that the
# event loop will no longer monitor it.
def stop_listening_to(io)
listeners.delete(io)
end
-
+
# Returns a reference to the Net::SSH::Service::Forward service, which can
# be used for forwarding ports over SSH.
def forward
@forward ||= Service::Forward.new(self)
end
-
+
# Registers a handler to be invoked when the server wants to open a
# channel on the client. The callback receives the connection object,
# the new channel object, and the packet itself as arguments, and should
@@ -506,7 +507,7 @@ module Net
def on_open_channel(type, &block)
channel_open_handlers[type] = block
end
-
+
# Registers a handler to be invoked when the server sends a global request
# of the given type. The callback receives the request data as the first
# parameter, and true/false as the second (indicating whether a response
@@ -517,61 +518,61 @@ module Net
old, @on_global_request[type] = @on_global_request[type], block
old
end
-
+
def cleanup_channel(channel)
if channel.local_closed? and channel.remote_closed?
info { "#{host} delete channel #{channel.local_id} which closed locally and remotely" }
channels.delete(channel.local_id)
end
end
-
+
# If the #preprocess and #postprocess callbacks for this session need to run
# periodically, this method returns the maximum number of seconds which may
# pass between callbacks.
def max_select_wait_time
@keepalive.interval if @keepalive.enabled?
end
-
+
private
-
+
# iterate channels with the posibility of callbacks opening new channels during the iteration
def each_channel(&block)
channels.dup.each(&block)
end
-
+
# Read all pending packets from the connection and dispatch them as
# appropriate. Returns as soon as there are no more pending packets.
def dispatch_incoming_packets(raise_disconnect_errors: true)
while packet = transport.poll_message
raise Net::SSH::Exception, "unexpected response #{packet.type} (#{packet.inspect})" unless MAP.key?(packet.type)
-
+
send(MAP[packet.type], packet)
end
rescue StandardError
force_channel_cleanup_on_close if closed?
raise if raise_disconnect_errors || !$!.is_a?(Net::SSH::Disconnect)
end
-
+
# Returns the next available channel id to be assigned, and increments
# the counter.
def get_next_channel_id
@channel_id_counter += 1
end
-
+
def force_channel_cleanup_on_close
channels.each do |id, channel|
channel_closed(channel)
end
end
-
+
def channel_closed(channel)
channel.remote_closed!
channel.close
-
+
cleanup_channel(channel)
channel.do_close
end
-
+
# Invoked when a global request is received. The registered global
# request callback will be invoked, if one exists, and the necessary
# reply returned.
@@ -583,41 +584,41 @@ module Net
if result != :sent && result != true && result != false
raise "expected global request handler for `#{packet[:request_type]}' to return true, false, or :sent, but got #{result.inspect}"
end
-
+
if packet[:want_reply] && result != :sent
msg = Buffer.from(:byte, result ? REQUEST_SUCCESS : REQUEST_FAILURE)
send_message(msg)
end
end
-
+
# Invokes the next pending request callback with +true+.
def request_success(packet)
info { "global request success" }
callback = pending_requests.shift
callback.call(true, packet) if callback
end
-
+
# Invokes the next pending request callback with +false+.
def request_failure(packet)
info { "global request failure" }
callback = pending_requests.shift
callback.call(false, packet) if callback
end
-
+
# Called when the server wants to open a channel. If no registered
# channel handler exists for the given channel type, CHANNEL_OPEN_FAILURE
# is returned, otherwise the callback is invoked and everything proceeds
# accordingly.
def channel_open(packet)
info { "channel open #{packet[:channel_type]}" }
-
+
local_id = get_next_channel_id
-
+
channel = Channel.new(self, packet[:channel_type], local_id, @max_pkt_size, @max_win_size)
channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size])
-
+
callback = channel_open_handlers[packet[:channel_type]]
-
+
if callback
begin
callback[self, channel, packet]
@@ -632,80 +633,80 @@ module Net
else
failure = [3, "unknown channel type #{channel.type}"]
end
-
+
if failure
error { failure.inspect }
msg = Buffer.from(:byte, CHANNEL_OPEN_FAILURE, :long, channel.remote_id, :long, failure[0], :string, failure[1], :string, "")
end
-
+
send_message(msg)
end
-
+
def channel_open_confirmation(packet)
info { "channel_open_confirmation: #{packet[:local_id]} #{packet[:remote_id]} #{packet[:window_size]} #{packet[:packet_size]}" }
channel = channels[packet[:local_id]]
channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size])
end
-
+
def channel_open_failure(packet)
error { "channel_open_failed: #{packet[:local_id]} #{packet[:reason_code]} #{packet[:description]}" }
channel = channels.delete(packet[:local_id])
channel.do_open_failed(packet[:reason_code], packet[:description])
end
-
+
def channel_window_adjust(packet)
info { "channel_window_adjust: #{packet[:local_id]} +#{packet[:extra_bytes]}" }
channels[packet[:local_id]].do_window_adjust(packet[:extra_bytes])
end
-
+
def channel_request(packet)
info { "channel_request: #{packet[:local_id]} #{packet[:request]} #{packet[:want_reply]}" }
channels[packet[:local_id]].do_request(packet[:request], packet[:want_reply], packet[:request_data])
end
-
+
def channel_data(packet)
info { "channel_data: #{packet[:local_id]} #{packet[:data].length}b" }
channels[packet[:local_id]].do_data(packet[:data])
end
-
+
def channel_extended_data(packet)
info { "channel_extended_data: #{packet[:local_id]} #{packet[:data_type]} #{packet[:data].length}b" }
channels[packet[:local_id]].do_extended_data(packet[:data_type], packet[:data])
end
-
+
def channel_eof(packet)
info { "channel_eof: #{packet[:local_id]}" }
channels[packet[:local_id]].do_eof
end
-
+
def channel_close(packet)
info { "channel_close: #{packet[:local_id]}" }
-
+
channel = channels[packet[:local_id]]
channel_closed(channel)
end
-
+
def channel_success(packet)
info { "channel_success: #{packet[:local_id]}" }
channels[packet[:local_id]].do_success
end
-
+
def channel_failure(packet)
info { "channel_failure: #{packet[:local_id]}" }
channels[packet[:local_id]].do_failure
end
-
+
def io_select_wait(wait)
[wait, max_select_wait_time].compact.min
end
-
+
MAP = Constants.constants.each_with_object({}) do |name, memo|
value = const_get(name)
next unless Integer === value
+
memo[value] = name.downcase.to_sym
end
end
-
end
end
end
diff --git a/lib/net/ssh/connection/term.rb b/lib/net/ssh/connection/term.rb
index 5b5a7de..d4abad1 100644
--- a/lib/net/ssh/connection/term.rb
+++ b/lib/net/ssh/connection/term.rb
@@ -1,7 +1,6 @@
-module Net
- module SSH
+module Net
+ module SSH
module Connection
-
# These constants are used when requesting a pseudo-terminal (via
# Net::SSH::Connection::Channel#request_pty). The descriptions for each are
# taken directly from RFC 4254 ("The Secure Shell (SSH) Connection Protocol"),
@@ -10,173 +9,172 @@ module Net
# Interrupt character; 255 if none. Similarly for the other characters.
# Not all of these characters are supported on all systems.
VINTR = 1
-
+
# The quit character (sends SIGQUIT signal on POSIX systems).
VQUIT = 2
-
+
# Erase the character to left of the cursor.
VERASE = 3
-
+
# Kill the current input line.
VKILL = 4
-
+
# End-of-file character (sends EOF from the terminal).
VEOF = 5
-
+
# End-of-line character in addition to carriage return and/or linefeed.
VEOL = 6
-
+
# Additional end-of-line character.
VEOL2 = 7
-
+
# Continues paused output (normally control-Q).
VSTART = 8
-
+
# Pauses output (normally control-S).
VSTOP = 9
-
+
# Suspends the current program.
VSUSP = 10
-
+
# Another suspend character.
VDSUSP = 11
-
+
# Reprints the current input line.
VREPRINT = 12
-
+
# Erases a word left of cursor.
VWERASE = 13
-
+
# Enter the next character typed literally, even if it is a special
# character.
VLNEXT = 14
-
+
# Character to flush output.
VFLUSH = 15
-
+
# Switch to a different shell layer.
VSWITCH = 16
-
+
# Prints system status line (load, command, pid, etc).
VSTATUS = 17
-
+
# Toggles the flushing of terminal output.
VDISCARD = 18
-
+
# The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE,
# and 1 if it is TRUE.
IGNPAR = 30
-
+
# Mark parity and framing errors.
PARMRK = 31
-
+
# Enable checking of parity errors.
INPCK = 32
-
+
# Strip 8th bit off characters.
ISTRIP = 33
-
+
# Map NL into CR on input.
INCLR = 34
-
+
# Ignore CR on input.
IGNCR = 35
-
+
# Map CR to NL on input.
ICRNL = 36
-
+
# Translate uppercase characters to lowercase.
IUCLC = 37
-
+
# Enable output flow control.
IXON = 38
-
+
# Any char will restart after stop.
IXANY = 39
-
+
# Enable input flow control.
IXOFF = 40
-
+
# Ring bell on input queue full.
IMAXBEL = 41
-
+
# Enable signals INTR, QUIT, [D]SUSP.
ISIG = 50
-
+
# Canonicalize input lines.
ICANON = 51
-
+
# Enable input and output of uppercase characters by preceding their
# lowercase equivalents with "\".
XCASE = 52
-
+
# Enable echoing.
ECHO = 53
-
+
# Visually erase chars.
ECHOE = 54
-
+
# Kill character discards current line.
ECHOK = 55
-
+
# Echo NL even if ECHO is off.
ECHONL = 56
-
+
# Don't flush after interrupt.
NOFLSH = 57
-
+
# Stop background jobs from output.
TOSTOP = 58
-
+
# Enable extensions.
IEXTEN = 59
-
+
# Echo control characters as ^(Char).
ECHOCTL = 60
-
+
# Visual erase for line kill.
ECHOKE = 61
-
+
# Retype pending input.
PENDIN = 62
-
+
# Enable output processing.
OPOST = 70
-
+
# Convert lowercase to uppercase.
OLCUC = 71
-
+
# Map NL to CR-NL.
ONLCR = 72
-
+
# Translate carriage return to newline (output).
OCRNL = 73
-
+
# Translate newline to carriage return-newline (output).
ONOCR = 74
-
+
# Newline performs a carriage return (output).
ONLRET = 75
-
+
# 7 bit mode.
CS7 = 90
-
+
# 8 bit mode.
CS8 = 91
-
+
# Parity enable.
PARENB = 92
-
+
# Odd parity, else even.
PARODD = 93
-
+
# Specifies the input baud rate in bits per second.
TTY_OP_ISPEED = 128
-
+
# Specifies the output baud rate in bits per second.
TTY_OP_OSPEED = 129
end
-
end
end
end
diff --git a/lib/net/ssh/errors.rb b/lib/net/ssh/errors.rb
index 8fa8a4b..7455fed 100644
--- a/lib/net/ssh/errors.rb
+++ b/lib/net/ssh/errors.rb
@@ -1,4 +1,4 @@
-module Net
+module Net
module SSH
# A general exception class, to act as the ancestor of all other Net::SSH
# exception classes.
@@ -33,7 +33,7 @@ module Net
# a "channel open failed" message.
class ChannelOpenFailed < Net::SSH::Exception
attr_reader :code, :reason
-
+
def initialize(code, reason)
@code, @reason = code, reason
super "#{reason} (#{code})"
@@ -45,43 +45,43 @@ module Net
# the remember_host! method on the exception, and then retry.
class HostKeyError < Net::SSH::Exception
# the callback to use when #remember_host! is called
- attr_writer :callback #:nodoc:
-
+ attr_writer :callback # :nodoc:
+
# situation-specific data describing the host (see #host, #port, etc.)
- attr_writer :data #:nodoc:
-
+ attr_writer :data # :nodoc:
+
# An accessor for getting at the data that was used to look up the host
# (see also #fingerprint, #host, #port, #ip, and #key).
def [](key)
@data && @data[key]
end
-
+
# Returns the fingerprint of the key for the host, which either was not
# found or did not match.
def fingerprint
@data && @data[:fingerprint]
end
-
+
# Returns the host name for the remote host, as reported by the socket.
def host
@data && @data[:peer] && @data[:peer][:host]
end
-
+
# Returns the port number for the remote host, as reported by the socket.
def port
@data && @data[:peer] && @data[:peer][:port]
end
-
+
# Returns the IP address of the remote host, as reported by the socket.
def ip
@data && @data[:peer] && @data[:peer][:ip]
end
-
+
# Returns the key itself, as reported by the remote host.
def key
@data && @data[:key]
end
-
+
# Tell Net::SSH to record this host and key in the known hosts file, so
# that subsequent connections will remember them.
def remember_host!
diff --git a/lib/net/ssh/key_factory.rb b/lib/net/ssh/key_factory.rb
index 04dac98..5d5cfbf 100644
--- a/lib/net/ssh/key_factory.rb
+++ b/lib/net/ssh/key_factory.rb
@@ -5,7 +5,6 @@ require 'net/ssh/authentication/ed25519_loader'
module Net
module SSH
-
# A factory class for returning new Key classes. It is used for obtaining
# OpenSSL key instances via their SSH names, and for loading both public and
# private keys. It used used primarily by Net::SSH itself, internally, and
@@ -18,14 +17,14 @@ module Net
class KeyFactory
# Specifies the mapping of SSH names to OpenSSL key classes.
MAP = {
- 'dh' => OpenSSL::PKey::DH,
- 'rsa' => OpenSSL::PKey::RSA,
- 'dsa' => OpenSSL::PKey::DSA,
+ 'dh' => OpenSSL::PKey::DH,
+ 'rsa' => OpenSSL::PKey::RSA,
+ 'dsa' => OpenSSL::PKey::DSA,
'ecdsa' => OpenSSL::PKey::EC
}
MAP["ed25519"] = Net::SSH::Authentication::ED25519::PrivKey if defined? Net::SSH::Authentication::ED25519
- class <<self
+ class << self
# Fetch an OpenSSL key instance by its SSH name. It will be a new,
# empty key of the given type.
def get(name)
@@ -37,7 +36,7 @@ module Net
# appropriately. The new key is returned. If the key itself is
# encrypted (requiring a passphrase to use), the user will be
# prompted to enter their password unless passphrase works.
- def load_private_key(filename, passphrase=nil, ask_passphrase=true, prompt=Prompt.default)
+ def load_private_key(filename, passphrase = nil, ask_passphrase = true, prompt = Prompt.default)
data = File.read(File.expand_path(filename))
load_data_private_key(data, passphrase, ask_passphrase, filename, prompt)
end
@@ -47,7 +46,7 @@ module Net
# appropriately. The new key is returned. If the key itself is
# encrypted (requiring a passphrase to use), the user will be
# prompted to enter their password unless passphrase works.
- def load_data_private_key(data, passphrase=nil, ask_passphrase=true, filename="", prompt=Prompt.default)
+ def load_data_private_key(data, passphrase = nil, ask_passphrase = true, filename = "", prompt = Prompt.default)
key_type = classify_key(data, filename)
encrypted_key = nil
@@ -87,7 +86,7 @@ module Net
# Loads a public key. It will correctly determine whether
# the file describes an RSA or DSA key, and will load it
# appropriately. The new public key is returned.
- def load_data_public_key(data, filename="")
+ def load_data_public_key(data, filename = "")
fields = data.split(/ /)
blob = nil
diff --git a/lib/net/ssh/known_hosts.rb b/lib/net/ssh/known_hosts.rb
index 23a5606..eeb8635 100644
--- a/lib/net/ssh/known_hosts.rb
+++ b/lib/net/ssh/known_hosts.rb
@@ -6,6 +6,63 @@ require 'net/ssh/authentication/ed25519_loader'
module Net
module SSH
+ module HostKeyEntries
+ # regular public key entry
+ class PubKey < Delegator
+ def initialize(key, comment: nil) # rubocop:disable Lint/MissingSuper
+ @key = key
+ @comment = comment
+ end
+
+ def ssh_type
+ @key.ssh_type
+ end
+
+ def ssh_types
+ [ssh_type]
+ end
+
+ def to_blob
+ @key.to_blob
+ end
+
+ def __getobj__
+ Kernel.warn("Calling Net::SSH::Buffer methods on HostKeyEntries PubKey is deprecated")
+ @key
+ end
+
+ def matches_key?(server_key)
+ @key.ssh_type == server_key.ssh_type && @key.to_blob == server_key.to_blob
+ end
+ end
+
+ # @cert-authority entry
+ class CertAuthority
+ def ssh_types
+ %w[
+ ecdsa-sha2-nistp256-cert-v01@openssh.com
+ ecdsa-sha2-nistp384-cert-v01@openssh.com
+ ecdsa-sha2-nistp521-cert-v01@openssh.com
+ ssh-ed25519-cert-v01@openssh.com
+ ssh-rsa-cert-v01@openssh.com
+ ssh-rsa-cert-v00@openssh.com
+ ]
+ end
+
+ def initialize(key, comment: nil)
+ @key = key
+ @comment = comment
+ end
+
+ def matches_key?(server_key)
+ if ssh_types.include?(server_key.ssh_type)
+ server_key.signature_valid? && (server_key.signature_key.to_blob == @key.to_blob)
+ else
+ false
+ end
+ end
+ end
+ end
# Represents the result of a search in known hosts
# see search_for
@@ -48,10 +105,10 @@ module Net
SUPPORTED_TYPE.push('ssh-ed25519') if Net::SSH::Authentication::ED25519Loader::LOADED
- class <<self
+ class << self
# Searches all known host files (see KnownHosts.hostfiles) for all keys
# of the given host. Returns an enumerable of keys found.
- def search_for(host, options={})
+ def search_for(host, options = {})
HostKeys.new(search_in(hostfiles(options), host, options), host, self, options)
end
@@ -70,7 +127,7 @@ module Net
#
# If you only want the user known host files, you can pass :user as
# the second option.
- def hostfiles(options, which=:all)
+ def hostfiles(options, which = :all)
files = []
files += Array(options[:user_known_hosts_file] || %w[~/.ssh/known_hosts ~/.ssh/known_hosts2]) if which == :all || which == :user
@@ -85,14 +142,12 @@ module Net
# Looks in all user known host files (see KnownHosts.hostfiles) and tries to
# add an entry for the given host and key to the first file it is able
# to.
- def add(host, key, options={})
+ def add(host, key, options = {})
hostfiles(options, :user).each do |file|
- begin
- KnownHosts.new(file).add(host, key)
- return
- rescue SystemCallError
- # try the next hostfile
- end
+ KnownHosts.new(file).add(host, key)
+ return
+ rescue SystemCallError
+ # try the next hostfile
end
end
end
@@ -130,7 +185,13 @@ module Net
File.open(source) do |file|
file.each_line do |line|
- hosts, type, key_content = line.split(' ')
+ if line.start_with?('@')
+ marker, hosts, type, key_content, comment = line.split(' ')
+ else
+ marker = nil
+ hosts, type, key_content, comment = line.split(' ')
+ end
+
# Skip empty line or one that is commented
next if hosts.nil? || hosts.start_with?('#')
@@ -145,7 +206,14 @@ module Net
next unless found
blob = key_content.unpack("m*").first
- keys << Net::SSH::Buffer.new(blob).read_key
+ raw_key = Net::SSH::Buffer.new(blob).read_key
+
+ keys <<
+ if marker == "@cert-authority"
+ HostKeyEntries::CertAuthority.new(raw_key, comment: comment)
+ else
+ HostKeyEntries::PubKey.new(raw_key, comment: comment)
+ end
end
end
@@ -155,11 +223,11 @@ module Net
def match(host, pattern)
if pattern.include?('*') || pattern.include?('?')
# see man 8 sshd for pattern details
- pattern_regexp = pattern.split('*').map do |x|
- x.split('?').map do |y|
+ pattern_regexp = pattern.split('*', -1).map do |x|
+ x.split('?', -1).map do |y|
Regexp.escape(y)
end.join('.')
- end.join('[^.]*')
+ end.join('.*')
host =~ Regexp.new("\\A#{pattern_regexp}\\z")
else
diff --git a/lib/net/ssh/loggable.rb b/lib/net/ssh/loggable.rb
index b9df4d5..49ea5dd 100644
--- a/lib/net/ssh/loggable.rb
+++ b/lib/net/ssh/loggable.rb
@@ -1,6 +1,5 @@
-module Net
+module Net
module SSH
-
# A simple module to make logging easier to deal with. It assumes that the
# logger instance (if not nil) quacks like a Logger object (in Ruby's
# standard library). Although used primarily internally by Net::SSH, it
@@ -19,39 +18,39 @@ module Net
# The logger instance that will be used to log messages. If nil, nothing
# will be logged.
attr_accessor :logger
-
+
# Displays the result of yielding if the log level is Logger::DEBUG or
# greater.
def debug
logger.add(Logger::DEBUG, nil, facility) { yield } if logger && logger.debug?
end
-
+
# Displays the result of yielding if the log level is Logger::INFO or
# greater.
def info
logger.add(Logger::INFO, nil, facility) { yield } if logger && logger.info?
end
-
+
# Displays the result of yielding if the log level is Logger::WARN or
# greater. (Called lwarn to avoid shadowing with Kernel#warn.)
def lwarn
logger.add(Logger::WARN, nil, facility) { yield } if logger && logger.warn?
end
-
+
# Displays the result of yielding if the log level is Logger:ERROR or
# greater.
def error
logger.add(Logger::ERROR, nil, facility) { yield } if logger && logger.error?
end
-
+
# Displays the result of yielding if the log level is Logger::FATAL or
# greater.
def fatal
logger.add(Logger::FATAL, nil, facility) { yield } if logger && logger.fatal?
end
-
+
private
-
+
# Sets the "facility" value, used for reporting where a log message
# originates. It defaults to the name of class with the object_id
# appended.
diff --git a/lib/net/ssh/packet.rb b/lib/net/ssh/packet.rb
index a379586..cc762ca 100644
--- a/lib/net/ssh/packet.rb
+++ b/lib/net/ssh/packet.rb
@@ -5,7 +5,6 @@ require 'net/ssh/connection/constants'
module Net
module SSH
-
# A specialization of Buffer that knows the format of certain common
# packet types. It auto-parses those packet types, and allows them to
# be accessed via the #[] accessor.
@@ -85,6 +84,7 @@ module Net
def [](name)
name = name.to_sym
raise ArgumentError, "no such element #{name}" unless @named_elements.key?(name)
+
@named_elements[name]
end
diff --git a/lib/net/ssh/prompt.rb b/lib/net/ssh/prompt.rb
index bffe458..a52463f 100644
--- a/lib/net/ssh/prompt.rb
+++ b/lib/net/ssh/prompt.rb
@@ -1,8 +1,7 @@
require 'io/console'
-module Net
+module Net
module SSH
-
# Default prompt implementation, called for asking password from user.
# It will never be instantiated directly, but will instead be created for
# you automatically.
@@ -13,8 +12,8 @@ module Net
#
# prompter = options[:password_prompt].start({type:'password'})
# while !ok && max_retries < 3
- # user = prompter.ask("user: ", {}, true)
- # password = prompter.ask("password: ", {}, false)
+ # user = prompter.ask("user: ", true)
+ # password = prompter.ask("password: ", false)
# ok = send(user, password)
# prompter.sucess if ok
# end
@@ -24,9 +23,9 @@ module Net
def self.default(options = {})
@default ||= new(options)
end
-
+
def initialize(options = {}); end
-
+
# default prompt object implementation. More sophisticated implemenetations
# might implement caching.
class Prompter
@@ -36,22 +35,22 @@ module Net
$stdout.puts(info[:instruction]) unless info[:instruction].empty?
end
end
-
+
# ask input from user, a prompter might ask for multiple inputs
# (like user and password) in a single session.
- def ask(prompt, echo=true)
+ def ask(prompt, echo = true)
$stdout.print(prompt)
$stdout.flush
ret = $stdin.noecho(&:gets).chomp
$stdout.print("\n")
ret
end
-
+
# success method will be called when the password was accepted
# It's a good time to save password asked to a cache.
def success; end
end
-
+
# start password session. Multiple questions might be asked multiple times
# on the returned object. Info hash tries to uniquely identify the password
# session, so caching implementations can save passwords properly.
@@ -59,6 +58,5 @@ module Net
Prompter.new(info)
end
end
-
end
end
diff --git a/lib/net/ssh/proxy/command.rb b/lib/net/ssh/proxy/command.rb
index 1bb2423..d6a89dd 100644
--- a/lib/net/ssh/proxy/command.rb
+++ b/lib/net/ssh/proxy/command.rb
@@ -5,7 +5,6 @@ require 'net/ssh/proxy/errors'
module Net
module SSH
module Proxy
-
# An implementation of a command proxy. To use it, instantiate it,
# then pass the instantiated object via the :proxy key to
# Net::SSH.start:
@@ -105,6 +104,7 @@ module Net
if IO.select([self], nil, [self], timeout_in_seconds) == nil
raise "Unexpected spurious read wakeup"
end
+
retry
end
result
diff --git a/lib/net/ssh/proxy/errors.rb b/lib/net/ssh/proxy/errors.rb
index bbaf5dd..f696cf3 100644
--- a/lib/net/ssh/proxy/errors.rb
+++ b/lib/net/ssh/proxy/errors.rb
@@ -1,9 +1,8 @@
require 'net/ssh/errors'
-module Net
- module SSH
+module Net
+ module SSH
module Proxy
-
# A general exception class for all Proxy errors.
class Error < Net::SSH::Exception; end
@@ -12,7 +11,6 @@ module Net
# Used when the server doesn't recognize the user's credentials.
class UnauthorizedError < Error; end
-
end
end
end
diff --git a/lib/net/ssh/proxy/http.rb b/lib/net/ssh/proxy/http.rb
index 1cfaa62..fd9958e 100644
--- a/lib/net/ssh/proxy/http.rb
+++ b/lib/net/ssh/proxy/http.rb
@@ -1,10 +1,9 @@
require 'socket'
require 'net/ssh/proxy/errors'
-module Net
- module SSH
+module Net
+ module SSH
module Proxy
-
# An implementation of an HTTP proxy. To use it, instantiate it, then
# pass the instantiated object via the :proxy key to Net::SSH.start:
#
@@ -26,14 +25,14 @@ module Net
class HTTP
# The hostname or IP address of the HTTP proxy.
attr_reader :proxy_host
-
+
# The port number of the proxy.
attr_reader :proxy_port
-
+
# The map of additional options that were given to the object at
# initialization.
attr_reader :options
-
+
# Create a new socket factory that tunnels via the given host and
# port. The +options+ parameter is a hash of additional settings that
# can be used to tweak this proxy connection. Specifically, the following
@@ -41,52 +40,52 @@ module Net
#
# * :user => the user name to use when authenticating to the proxy
# * :password => the password to use when authenticating
- def initialize(proxy_host, proxy_port=80, options={})
+ def initialize(proxy_host, proxy_port = 80, options = {})
@proxy_host = proxy_host
@proxy_port = proxy_port
@options = options
end
-
+
# Return a new socket connected to the given host and port via the
# proxy that was requested when the socket factory was instantiated.
def open(host, port, connection_options)
socket = establish_connection(connection_options[:timeout])
socket.write "CONNECT #{host}:#{port} HTTP/1.1\r\n"
socket.write "Host: #{host}:#{port}\r\n"
-
+
if options[:user]
credentials = ["#{options[:user]}:#{options[:password]}"].pack("m*").gsub(/\s/, "")
socket.write "Proxy-Authorization: Basic #{credentials}\r\n"
end
-
+
socket.write "\r\n"
-
+
resp = parse_response(socket)
-
+
return socket if resp[:code] == 200
-
+
socket.close
raise ConnectError, resp.inspect
end
-
+
protected
-
+
def establish_connection(connect_timeout)
Socket.tcp(proxy_host, proxy_port, nil, nil,
connect_timeout: connect_timeout)
end
-
+
def parse_response(socket)
version, code, reason = socket.gets.chomp.split(/ /, 3)
headers = {}
-
+
while (line = socket.gets) && (line.chomp! != "")
name, value = line.split(/:/, 2)
headers[name.strip] = value.strip
end
-
+
body = socket.read(headers["Content-Length"].to_i) if headers["Content-Length"]
-
+
return { version: version,
code: code.to_i,
reason: reason,
@@ -94,7 +93,6 @@ module Net
body: body }
end
end
-
end
end
end
diff --git a/lib/net/ssh/proxy/https.rb b/lib/net/ssh/proxy/https.rb
index 298d537..2e12017 100644
--- a/lib/net/ssh/proxy/https.rb
+++ b/lib/net/ssh/proxy/https.rb
@@ -3,10 +3,9 @@ require 'openssl'
require 'net/ssh/proxy/errors'
require 'net/ssh/proxy/http'
-module Net
- module SSH
+module Net
+ module SSH
module Proxy
-
# A specialization of the HTTP proxy which encrypts the whole connection
# using OpenSSL. This has the advantage that proxy authentication
# information is not sent in plaintext.
@@ -17,27 +16,27 @@ module Net
# taken by Net::SSH::Proxy::HTTP it supports:
#
# * :ssl_context => the SSL configuration to use for the connection
- def initialize(proxy_host, proxy_port=80, options={})
+ def initialize(proxy_host, proxy_port = 80, options = {})
@ssl_context = options.delete(:ssl_context) ||
OpenSSL::SSL::SSLContext.new
super(proxy_host, proxy_port, options)
end
-
+
protected
-
+
# Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket
# for all intents and purposes of Net::SSH::BufferedIo
module SSLSocketCompatibility
- def self.extended(object) #:nodoc:
+ def self.extended(object) # :nodoc:
object.define_singleton_method(:recv, object.method(:sysread))
object.sync_close = true
end
-
+
def send(data, _opts)
syswrite(data)
end
end
-
+
def establish_connection(connect_timeout)
plain_socket = super(connect_timeout)
OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket|
@@ -46,7 +45,6 @@ module Net
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/proxy/jump.rb b/lib/net/ssh/proxy/jump.rb
index ab67e84..a5de7d9 100644
--- a/lib/net/ssh/proxy/jump.rb
+++ b/lib/net/ssh/proxy/jump.rb
@@ -1,10 +1,9 @@
require 'uri'
require 'net/ssh/proxy/command'
-module Net
- module SSH
+module Net
+ module SSH
module Proxy
-
# An implementation of a jump proxy. To use it, instantiate it,
# then pass the instantiated object via the :proxy key to
# Net::SSH.start:
@@ -18,39 +17,38 @@ module Net
class Jump < Command
# The jump proxies
attr_reader :jump_proxies
-
+
# Create a new socket factory that tunnels via multiple jump proxes as
# [user@]host[:port].
def initialize(jump_proxies)
@jump_proxies = jump_proxies
end
-
+
# Return a new socket connected to the given host and port via the jump
# proxy that was requested when the socket factory was instantiated.
def open(host, port, connection_options = nil)
build_proxy_command_equivalent(connection_options)
super
end
-
+
# We cannot build the ProxyCommand template until we know if the :config
# option was specified during `Net::SSH.start`.
def build_proxy_command_equivalent(connection_options = nil)
first_jump, extra_jumps = jump_proxies.split(",", 2)
config = connection_options && connection_options[:config]
uri = URI.parse("ssh://#{first_jump}")
-
- template = "ssh"
+
+ template = "ssh".dup
template << " -l #{uri.user}" if uri.user
template << " -p #{uri.port}" if uri.port
template << " -J #{extra_jumps}" if extra_jumps
template << " -F #{config}" if config != true && config
template << " -W %h:%p "
template << uri.host
-
+
@command_line_template = template
end
end
-
end
end
end
diff --git a/lib/net/ssh/proxy/socks4.rb b/lib/net/ssh/proxy/socks4.rb
index eac35b0..9f4476a 100644
--- a/lib/net/ssh/proxy/socks4.rb
+++ b/lib/net/ssh/proxy/socks4.rb
@@ -6,7 +6,6 @@ require 'net/ssh/proxy/errors'
module Net
module SSH
module Proxy
-
# An implementation of a SOCKS4 proxy. To use it, instantiate it, then
# pass the instantiated object via the :proxy key to Net::SSH.start:
#
@@ -38,7 +37,7 @@ module Net
# Create a new proxy connection to the given proxy host and port.
# Optionally, a :user key may be given to identify the username
# with which to authenticate.
- def initialize(proxy_host, proxy_port=1080, options={})
+ def initialize(proxy_host, proxy_port = 1080, options = {})
@proxy_host = proxy_host
@proxy_port = proxy_port
@options = options
@@ -50,7 +49,7 @@ module Net
socket = Socket.tcp(proxy_host, proxy_port, nil, nil,
connect_timeout: connection_options[:timeout])
ip_addr = IPAddr.new(Resolv.getaddress(host))
-
+
packet = [VERSION, CONNECT, port.to_i, ip_addr.to_i, options[:user]].pack("CCnNZ*")
socket.send packet, 0
@@ -63,7 +62,6 @@ module Net
return socket
end
end
-
end
end
end
diff --git a/lib/net/ssh/proxy/socks5.rb b/lib/net/ssh/proxy/socks5.rb
index 08f2a3c..1e66318 100644
--- a/lib/net/ssh/proxy/socks5.rb
+++ b/lib/net/ssh/proxy/socks5.rb
@@ -4,7 +4,6 @@ require 'net/ssh/proxy/errors'
module Net
module SSH
module Proxy
-
# An implementation of a SOCKS5 proxy. To use it, instantiate it, then
# pass the instantiated object via the :proxy key to Net::SSH.start:
#
@@ -53,7 +52,7 @@ module Net
# Create a new proxy connection to the given proxy host and port.
# Optionally, :user and :password options may be given to
# identify the username and password with which to authenticate.
- def initialize(proxy_host, proxy_port=1080, options={})
+ def initialize(proxy_host, proxy_port = 1080, options = {})
@proxy_host = proxy_host
@proxy_port = proxy_port
@options = options
@@ -94,7 +93,7 @@ module Net
packet << [port].pack("n")
socket.send packet, 0
-
+
version, reply, = socket.recv(2).unpack("C*")
socket.recv(1)
address_type = socket.recv(1).getbyte(0)
@@ -111,7 +110,7 @@ module Net
raise ConnectError, "Illegal response type"
end
portnum = socket.recv(2)
-
+
unless reply == SUCCESS
socket.close
raise ConnectError, "#{reply}"
@@ -136,7 +135,6 @@ module Net
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/service/forward.rb b/lib/net/ssh/service/forward.rb
index 4bb3ae6..8b2f0f9 100644
--- a/lib/net/ssh/service/forward.rb
+++ b/lib/net/ssh/service/forward.rb
@@ -3,7 +3,6 @@ require 'net/ssh/loggable'
module Net
module SSH
module Service
-
# This class implements various port forwarding services for use by
# Net::SSH clients. The Forward class should never need to be instantiated
# directly; instead, it should be accessed via the singleton instance
@@ -18,7 +17,7 @@ module Net
attr_reader :session
# A simple class for representing a requested remote forwarded port.
- Remote = Struct.new(:host, :port) #:nodoc:
+ Remote = Struct.new(:host, :port) # :nodoc:
# Instantiates a new Forward service instance atop the given connection
# service session. This will register new channel open handlers to handle
@@ -106,7 +105,7 @@ module Net
#
# ssh.forward.cancel_local(1234)
# ssh.forward.cancel_local(1234, "0.0.0.0")
- def cancel_local(port, bind_address="127.0.0.1")
+ def cancel_local(port, bind_address = "127.0.0.1")
socket = @local_forwarded_ports.delete([port, bind_address])
socket.shutdown rescue nil
socket.close rescue nil
@@ -215,7 +214,7 @@ module Net
# raise Net::SSH::Exception, "remote forwarding request failed"
# end
#
- def remote(port, host, remote_port, remote_host="127.0.0.1")
+ def remote(port, host, remote_port, remote_host = "127.0.0.1")
session.send_global_request("tcpip-forward", :string, remote_host, :long, remote_port) do |success, response|
if success
remote_port = response.read_long if remote_port == 0
@@ -249,7 +248,7 @@ module Net
#
# ssh.forward.cancel_remote(1234, "0.0.0.0")
# ssh.loop { ssh.forward.active_remotes.include?([1234, "0.0.0.0"]) }
- def cancel_remote(port, host="127.0.0.1")
+ def cancel_remote(port, host = "127.0.0.1")
session.send_global_request("cancel-tcpip-forward", :string, host, :long, port) do |success, response|
if success
@remote_forwarded_ports.delete([port, host])
@@ -290,6 +289,7 @@ module Net
# end
def agent(channel)
return if @agent_forwarded
+
@agent_forwarded = true
channel.send_channel_request("auth-agent-req@openssh.com") do |achannel, success|
@@ -388,12 +388,13 @@ module Net
originator_address = packet.read_string
originator_port = packet.read_long
+ puts "REMOTE 0: #{connected_port} #{connected_address} #{originator_address} #{originator_port}"
remote = @remote_forwarded_ports[[connected_port, connected_address]]
-
if remote.nil?
raise Net::SSH::ChannelOpenFailed.new(1, "unknown request from remote forwarded connection on #{connected_address}:#{connected_port}")
end
+ puts "REMOTE: #{remote.host} #{remote.port}"
client = TCPSocket.new(remote.host, remote.port)
info { "connected #{connected_address}:#{connected_port} originator #{originator_address}:#{originator_port}" }
@@ -420,7 +421,6 @@ module Net
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/test.rb b/lib/net/ssh/test.rb
index 47b5db4..cb727ba 100644
--- a/lib/net/ssh/test.rb
+++ b/lib/net/ssh/test.rb
@@ -5,7 +5,6 @@ require 'net/ssh/test/socket'
module Net
module SSH
-
# This module may be used in unit tests, for when you want to test that your
# SSH state machines are really doing what you expect they are doing. You will
# typically include this module in your unit test class, and then build a
@@ -57,21 +56,21 @@ module Net
# Returns the test socket instance to use for these tests (see
# Net::SSH::Test::Socket).
- def socket(options={})
+ def socket(options = {})
@socket ||= Net::SSH::Test::Socket.new
end
# Returns the connection session (Net::SSH::Connection::Session) for use
# in these tests. It is a fully functional SSH session, operating over
# a mock socket (#socket).
- def connection(options={})
+ def connection(options = {})
@connection ||= Net::SSH::Connection::Session.new(transport(options), options)
end
# Returns the transport session (Net::SSH::Transport::Session) for use
# in these tests. It is a fully functional SSH transport session, operating
# over a mock socket (#socket).
- def transport(options={})
+ def transport(options = {})
@transport ||= Net::SSH::Transport::Session.new(
options[:host] || "localhost",
options.merge(kex: "test", host_key: "ssh-rsa", append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
@@ -85,11 +84,11 @@ module Net
# the block passed to this assertion.
def assert_scripted
raise "there is no script to be processed" if socket.script.events.empty?
+
Net::SSH::Test::Extensions::IO.with_test_extension { yield }
assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still" \
"#{socket.script.events.length} pending"
end
end
-
end
end
diff --git a/lib/net/ssh/test/channel.rb b/lib/net/ssh/test/channel.rb
index ea17019..c3baa90 100644
--- a/lib/net/ssh/test/channel.rb
+++ b/lib/net/ssh/test/channel.rb
@@ -1,7 +1,6 @@
-module Net
- module SSH
+module Net
+ module SSH
module Test
-
# A mock channel, used for scripting actions in tests. It wraps a
# Net::SSH::Test::Script instance, and delegates to it for the most part.
# This class has little real functionality on its own, but rather acts as
@@ -19,34 +18,34 @@ module Net
class Channel
# The Net::SSH::Test::Script instance employed by this mock channel.
attr_reader :script
-
+
# Sets the local-id of this channel object (the id assigned by the client).
attr_writer :local_id
-
+
# Sets the remote-id of this channel object (the id assigned by the mock-server).
attr_writer :remote_id
-
+
# Creates a new Test::Channel instance on top of the given +script+ (which
# must be a Net::SSH::Test::Script instance).
def initialize(script)
@script = script
@local_id = @remote_id = nil
end
-
+
# Returns the local (client-assigned) id for this channel, or a Proc object
# that will return the local-id later if the local id has not yet been set.
# (See Net::SSH::Test::Packet#instantiate!.)
def local_id
@local_id || Proc.new { @local_id or raise "local-id has not been set yet!" }
end
-
+
# Returns the remote (server-assigned) id for this channel, or a Proc object
# that will return the remote-id later if the remote id has not yet been set.
# (See Net::SSH::Test::Packet#instantiate!.)
def remote_id
@remote_id || Proc.new { @remote_id or raise "remote-id has not been set yet!" }
end
-
+
# Because adjacent calls to #gets_data will sometimes cause the data packets
# to be concatenated (causing expectations in tests to fail), you may
# need to separate those calls with calls to #inject_remote_delay! (which
@@ -58,62 +57,62 @@ module Net
def inject_remote_delay!
gets_data("")
end
-
- # Scripts the sending of an "exec" channel request packet to the mock
+
+ # Scripts the sending of an "exec" channel request packet to the mock
# server. If +reply+ is true, then the server is expected to reply to the
# request, otherwise no response to this request will be sent. If +success+
# is +true+, then the request will be successful, otherwise a failure will
# be scripted.
#
# channel.sends_exec "ls -l"
- def sends_exec(command, reply=true, success=true)
+ def sends_exec(command, reply = true, success = true)
script.sends_channel_request(self, "exec", reply, command, success)
end
-
+
# Scripts the sending of a "subsystem" channel request packet to the mock
# server. See #sends_exec for a discussion of the meaning of the +reply+
# and +success+ arguments.
#
# channel.sends_subsystem "sftp"
- def sends_subsystem(subsystem, reply=true, success=true)
+ def sends_subsystem(subsystem, reply = true, success = true)
script.sends_channel_request(self, "subsystem", reply, subsystem, success)
end
-
+
# Scripts the sending of a data packet across the channel.
#
# channel.sends_data "foo"
def sends_data(data)
script.sends_channel_data(self, data)
end
-
+
# Scripts the sending of an EOF packet across the channel.
#
# channel.sends_eof
def sends_eof
script.sends_channel_eof(self)
end
-
+
# Scripts the sending of a "channel close" packet across the channel.
#
# channel.sends_close
def sends_close
script.sends_channel_close(self)
end
-
+
# Scripts the sending of a "request pty" request packet across the channel.
#
# channel.sends_request_pty
def sends_request_pty
script.sends_channel_request_pty(self)
end
-
+
# Scripts the reception of a channel data packet from the remote end.
#
# channel.gets_data "bar"
def gets_data(data)
script.gets_channel_data(self, data)
end
-
+
# Scripts the reception of a channel extended data packet from the remote
# end.
#
@@ -121,21 +120,21 @@ module Net
def gets_extended_data(data)
script.gets_channel_extended_data(self, data)
end
-
+
# Scripts the reception of an "exit-status" channel request packet.
#
# channel.gets_exit_status(127)
- def gets_exit_status(status=0)
+ def gets_exit_status(status = 0)
script.gets_channel_request(self, "exit-status", false, status)
end
-
+
# Scripts the reception of an EOF packet from the remote end.
#
# channel.gets_eof
def gets_eof
script.gets_channel_eof(self)
end
-
+
# Scripts the reception of a "channel close" packet from the remote end.
#
# channel.gets_close
@@ -143,7 +142,6 @@ module Net
script.gets_channel_close(self)
end
end
-
end
end
-end \ No newline at end of file
+end
diff --git a/lib/net/ssh/test/extensions.rb b/lib/net/ssh/test/extensions.rb
index 5090f6c..733a531 100644
--- a/lib/net/ssh/test/extensions.rb
+++ b/lib/net/ssh/test/extensions.rb
@@ -6,16 +6,14 @@ require 'net/ssh/connection/constants'
require 'net/ssh/transport/constants'
require 'net/ssh/transport/packet_stream'
-module Net
- module SSH
+module Net
+ module SSH
module Test
-
# A collection of modules used to extend/override the default behavior of
# Net::SSH internals for ease of testing. As a consumer of Net::SSH, you'll
# never need to use this directly--they're all used under the covers by
# the Net::SSH::Test system.
module Extensions
-
# An extension to Net::SSH::BufferedIo (assumes that the underlying IO
# is actually a StringIO). Facilitates unit testing.
module BufferedIo
@@ -24,80 +22,82 @@ module Net
def select_for_read?
pos < size
end
-
+
# Set this to +true+ if you want the IO to pretend to be available for writing
attr_accessor :select_for_write
-
+
# Set this to +true+ if you want the IO to pretend to be in an error state
attr_accessor :select_for_error
-
+
alias select_for_write? select_for_write
alias select_for_error? select_for_error
end
-
+
# An extension to Net::SSH::Transport::PacketStream (assumes that the
# underlying IO is actually a StringIO). Facilitates unit testing.
module PacketStream
include BufferedIo # make sure we get the extensions here, too
-
- def self.included(base) #:nodoc:
+
+ def self.included(base) # :nodoc:
base.send :alias_method, :real_available_for_read?, :available_for_read?
base.send :alias_method, :available_for_read?, :test_available_for_read?
-
+
base.send :alias_method, :real_enqueue_packet, :enqueue_packet
base.send :alias_method, :enqueue_packet, :test_enqueue_packet
-
+
base.send :alias_method, :real_poll_next_packet, :poll_next_packet
base.send :alias_method, :poll_next_packet, :test_poll_next_packet
end
-
+
# Called when another packet should be inspected from the current
# script. If the next packet is a remote packet, it pops it off the
# script and shoves it onto this IO object, making it available to
# be read.
def idle!
return false unless script.next(:first)
-
+
if script.next(:first).remote?
self.string << script.next.to_s
self.pos = pos
end
-
+
return true
end
-
+
# The testing version of Net::SSH::Transport::PacketStream#available_for_read?.
# Returns true if there is data pending to be read. Otherwise calls #idle!.
def test_available_for_read?
return true if select_for_read?
+
idle!
false
end
-
+
# The testing version of Net::SSH::Transport::PacketStream#enqueued_packet.
# Simply calls Net::SSH::Test::Script#process on the packet.
def test_enqueue_packet(payload)
packet = Net::SSH::Buffer.new(payload.to_s)
script.process(packet)
end
-
+
# The testing version of Net::SSH::Transport::PacketStream#poll_next_packet.
# Reads the next available packet from the IO object and returns it.
def test_poll_next_packet
return nil if available <= 0
+
packet = Net::SSH::Buffer.new(read_available(4))
length = packet.read_long
Net::SSH::Packet.new(read_available(length))
end
end
-
+
# An extension to Net::SSH::Connection::Channel. Facilitates unit testing.
module Channel
- def self.included(base) #:nodoc:
+ def self.included(base) # :nodoc:
base.send :alias_method, :send_data_for_real, :send_data
base.send :alias_method, :send_data, :send_data_for_test
end
-
+
# The testing version of Net::SSH::Connection::Channel#send_data. Calls
# the original implementation, and then immediately enqueues the data for
# output so that scripted sends are properly interpreted as discrete
@@ -107,16 +107,16 @@ module Net
enqueue_pending_output
end
end
-
+
# An extension to the built-in ::IO class. Simply redefines IO.select
# so that it can be scripted in Net::SSH unit tests.
module IO
- def self.included(base) #:nodoc:
+ def self.included(base) # :nodoc:
base.extend(ClassMethods)
end
-
+
@extension_enabled = false
-
+
def self.with_test_extension(&block)
orig_value = @extension_enabled
@extension_enabled = true
@@ -126,35 +126,36 @@ module Net
@extension_enabled = orig_value
end
end
-
+
def self.extension_enabled?
@extension_enabled
end
-
+
module ClassMethods
- def self.extended(obj) #:nodoc:
- class <<obj
+ def self.extended(obj) # :nodoc:
+ class << obj
alias_method :select_for_real, :select
alias_method :select, :select_for_test
end
end
-
+
# The testing version of ::IO.select. Assumes that all readers,
# writers, and errors arrays are either nil, or contain only objects
# that mix in Net::SSH::Test::Extensions::BufferedIo.
- def select_for_test(readers=nil, writers=nil, errors=nil, wait=nil)
+ def select_for_test(readers = nil, writers = nil, errors = nil, wait = nil)
return select_for_real(readers, writers, errors, wait) unless Net::SSH::Test::Extensions::IO.extension_enabled?
+
ready_readers = Array(readers).select { |r| r.select_for_read? }
ready_writers = Array(writers).select { |r| r.select_for_write? }
ready_errors = Array(errors).select { |r| r.select_for_error? }
-
+
return [ready_readers, ready_writers, ready_errors] if ready_readers.any? || ready_writers.any? || ready_errors.any?
-
+
processed = 0
Array(readers).each do |reader|
processed += 1 if reader.idle!
end
-
+
raise "no readers were ready for reading, and none had any incoming packets" if processed == 0 && wait != 0
[[], [], []]
@@ -162,7 +163,6 @@ module Net
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/test/kex.rb b/lib/net/ssh/test/kex.rb
index 415f841..9e6f5be 100644
--- a/lib/net/ssh/test/kex.rb
+++ b/lib/net/ssh/test/kex.rb
@@ -5,10 +5,9 @@ require 'net/ssh/transport/algorithms'
require 'net/ssh/transport/constants'
require 'net/ssh/transport/kex'
-module Net
- module SSH
+module Net
+ module SSH
module Test
-
# An implementation of a key-exchange strategy specifically for unit tests.
# (This strategy would never really work against a real SSH server--it makes
# too many assumptions about the server's response.)
@@ -17,29 +16,28 @@ module Net
# "test" algorithm.
class Kex
include Net::SSH::Transport::Constants
-
+
# Creates a new instance of the testing key-exchange algorithm with the
# given arguments.
def initialize(algorithms, connection, data)
@connection = connection
end
-
+
# Exchange keys with the server. This returns a hash of constant values,
# and does not actually exchange keys.
def exchange_keys
result = Net::SSH::Buffer.from(:byte, NEWKEYS)
@connection.send_message(result)
-
+
buffer = @connection.next_message
raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
-
+
{ session_id: "abc-xyz",
server_key: OpenSSL::PKey::RSA.new(512),
shared_secret: OpenSSL::BN.new("1234567890", 10),
hashing_algorithm: OpenSSL::Digest::SHA1 }
end
end
-
end
end
end
diff --git a/lib/net/ssh/test/local_packet.rb b/lib/net/ssh/test/local_packet.rb
index 998edb7..edcdd48 100644
--- a/lib/net/ssh/test/local_packet.rb
+++ b/lib/net/ssh/test/local_packet.rb
@@ -4,7 +4,6 @@ require 'net/ssh/test/packet'
module Net
module SSH
module Test
-
# This is a specialization of Net::SSH::Test::Packet for representing mock
# packets that are sent from the local (client) host. These are created
# automatically by Net::SSH::Test::Script and Net::SSH::Test::Channel by any
@@ -49,7 +48,6 @@ module Net
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/test/packet.rb b/lib/net/ssh/test/packet.rb
index 8d7dc8c..da5a986 100644
--- a/lib/net/ssh/test/packet.rb
+++ b/lib/net/ssh/test/packet.rb
@@ -4,7 +4,6 @@ require 'net/ssh/transport/constants'
module Net
module SSH
module Test
-
# This is an abstract class, not to be instantiated directly, subclassed by
# Net::SSH::Test::LocalPacket and Net::SSH::Test::RemotePacket. It implements
# functionality common to those subclasses.
@@ -70,7 +69,7 @@ module Net
# added. Unsupported packet types will otherwise raise an exception.
def types
@types ||= case @type
- when KEXINIT then
+ when KEXINIT
%i[long long long long
string string string string string string string string string string
bool]
@@ -83,13 +82,14 @@ module Net
when CHANNEL_REQUEST
parts = %i[long string bool]
case @data[1]
- when "exec", "subsystem","shell" then parts << :string
+ when "exec", "subsystem", "shell" then parts << :string
when "exit-status" then parts << :long
when "pty-req" then parts.concat(%i[string long long long long string])
when "env" then parts.contact(%i[string string])
else
request = Packet.registered_channel_requests(@data[1])
raise "don't know what to do about #{@data[1]} channel request" unless request
+
parts.concat(request[:extra_parts])
end
else raise "don't know how to parse packet type #{@type}"
diff --git a/lib/net/ssh/test/remote_packet.rb b/lib/net/ssh/test/remote_packet.rb
index 90f6008..8f7bde2 100644
--- a/lib/net/ssh/test/remote_packet.rb
+++ b/lib/net/ssh/test/remote_packet.rb
@@ -1,10 +1,9 @@
require 'net/ssh/buffer'
require 'net/ssh/test/packet'
-module Net
- module SSH
+module Net
+ module SSH
module Test
-
# This is a specialization of Net::SSH::Test::Packet for representing mock
# packets that are received by the local (client) host. These are created
# automatically by Net::SSH::Test::Script and Net::SSH::Test::Channel by any
@@ -14,7 +13,7 @@ module Net
def remote?
true
end
-
+
# The #process method should only be called on Net::SSH::Test::LocalPacket
# packets; if it is attempted on a remote packet, then it is an expectation
# mismatch (a remote packet was received when a local packet was expected
@@ -23,8 +22,8 @@ module Net
def process(packet)
raise "received packet type #{packet.read_byte} and was not expecting any packet"
end
-
- # Returns this remote packet as a string, suitable for parsing by
+
+ # Returns this remote packet as a string, suitable for parsing by
# Net::SSH::Transport::PacketStream and friends. When a remote packet is
# received, this method is called and the result concatenated onto the
# input buffer for the packet stream.
@@ -36,7 +35,6 @@ module Net
end
end
end
-
end
end
-end \ No newline at end of file
+end
diff --git a/lib/net/ssh/test/script.rb b/lib/net/ssh/test/script.rb
index 4c51a7d..7eee90a 100644
--- a/lib/net/ssh/test/script.rb
+++ b/lib/net/ssh/test/script.rb
@@ -2,10 +2,9 @@ require 'net/ssh/test/channel'
require 'net/ssh/test/local_packet'
require 'net/ssh/test/remote_packet'
-module Net
- module SSH
+module Net
+ module SSH
module Test
-
# Represents a sequence of scripted events that identify the behavior that
# a test expects. Methods named "sends_*" create events for packets being
# sent from the local to the remote host, and methods named "gets_*" create
@@ -22,41 +21,41 @@ module Net
# The list of scripted events. These will be Net::SSH::Test::LocalPacket
# and Net::SSH::Test::RemotePacket instances.
attr_reader :events
-
+
# Create a new, empty script.
def initialize
@events = []
end
-
+
# Scripts the opening of a channel by adding a local packet sending the
# channel open request, and if +confirm+ is true (the default), also
# adding a remote packet confirming the new channel.
#
# A new Net::SSH::Test::Channel instance is returned, which can be used
# to script additional channel operations.
- def opens_channel(confirm=true)
+ def opens_channel(confirm = true)
channel = Channel.new(self)
channel.remote_id = 5555
-
+
events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
-
+
events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000) if confirm
-
+
channel
end
-
+
# A convenience method for adding an arbitrary local packet to the events
# list.
def sends(type, *args, &block)
events << LocalPacket.new(type, *args, &block)
end
-
+
# A convenience method for adding an arbitrary remote packet to the events
# list.
def gets(type, *args)
events << RemotePacket.new(type, *args)
end
-
+
# Scripts the sending of a new channel request packet to the remote host.
# +channel+ should be an instance of Net::SSH::Test::Channel. +request+
# is a string naming the request type to send, +reply+ is a boolean
@@ -71,7 +70,7 @@ module Net
#
# This will typically be called via Net::SSH::Test::Channel#sends_exec or
# Net::SSH::Test::Channel#sends_subsystem.
- def sends_channel_request(channel, request, reply, data, success=true)
+ def sends_channel_request(channel, request, reply, data, success = true)
if data.is_a? Array
events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, *data)
else
@@ -85,7 +84,7 @@ module Net
end
end
end
-
+
# Scripts the sending of a channel data packet. +channel+ must be a
# Net::SSH::Test::Channel object, and +data+ is the (string) data to
# expect will be sent.
@@ -94,21 +93,21 @@ module Net
def sends_channel_data(channel, data)
events << LocalPacket.new(:channel_data, channel.remote_id, data)
end
-
+
# Scripts the sending of a channel EOF packet from the given
# Net::SSH::Test::Channel +channel+. This will typically be called via
# Net::SSH::Test::Channel#sends_eof.
def sends_channel_eof(channel)
events << LocalPacket.new(:channel_eof, channel.remote_id)
end
-
+
# Scripts the sending of a channel close packet from the given
# Net::SSH::Test::Channel +channel+. This will typically be called via
# Net::SSH::Test::Channel#sends_close.
def sends_channel_close(channel)
events << LocalPacket.new(:channel_close, channel.remote_id)
end
-
+
# Scripts the sending of a channel request pty packets from the given
# Net::SSH::Test::Channel +channel+. This will typically be called via
# Net::SSH::Test::Channel#sends_request_pty.
@@ -117,14 +116,14 @@ module Net
data += Net::SSH::Connection::Channel::VALID_PTY_OPTIONS.merge(modes: "\0").values
events << LocalPacket.new(:channel_request, channel.remote_id, *data)
end
-
+
# Scripts the reception of a channel data packet from the remote host by
# the given Net::SSH::Test::Channel +channel+. This will typically be
# called via Net::SSH::Test::Channel#gets_data.
def gets_channel_data(channel, data)
events << RemotePacket.new(:channel_data, channel.local_id, data)
end
-
+
# Scripts the reception of a channel extended data packet from the remote
# host by the given Net::SSH::Test::Channel +channel+. This will typically
# be called via Net::SSH::Test::Channel#gets_extended_data.
@@ -133,28 +132,28 @@ module Net
def gets_channel_extended_data(channel, data)
events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
end
-
+
# Scripts the reception of a channel request packet from the remote host by
# the given Net::SSH::Test::Channel +channel+. This will typically be
# called via Net::SSH::Test::Channel#gets_exit_status.
def gets_channel_request(channel, request, reply, data)
events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data)
end
-
+
# Scripts the reception of a channel EOF packet from the remote host by
# the given Net::SSH::Test::Channel +channel+. This will typically be
# called via Net::SSH::Test::Channel#gets_eof.
def gets_channel_eof(channel)
events << RemotePacket.new(:channel_eof, channel.local_id)
end
-
+
# Scripts the reception of a channel close packet from the remote host by
# the given Net::SSH::Test::Channel +channel+. This will typically be
# called via Net::SSH::Test::Channel#gets_close.
def gets_channel_close(channel)
events << RemotePacket.new(:channel_close, channel.local_id)
end
-
+
# By default, removes the next event in the list and returns it. However,
# this can also be used to non-destructively peek at the next event in the
# list, by passing :first as the argument.
@@ -164,10 +163,10 @@ module Net
#
# # peek at the next event
# event = script.next(:first)
- def next(mode=:shift)
+ def next(mode = :shift)
events.send(mode)
end
-
+
# Compare the given packet against the next event in the list. If there is
# no next event, an exception will be raised. This is called by
# Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet.
@@ -176,7 +175,6 @@ module Net
event.process(packet)
end
end
-
end
end
-end \ No newline at end of file
+end
diff --git a/lib/net/ssh/test/socket.rb b/lib/net/ssh/test/socket.rb
index 57fe8f6..543a536 100644
--- a/lib/net/ssh/test/socket.rb
+++ b/lib/net/ssh/test/socket.rb
@@ -3,66 +3,63 @@ require 'stringio'
require 'net/ssh/test/extensions'
require 'net/ssh/test/script'
-module Net
- module SSH
+module Net
+ module SSH
module Test
-
# A mock socket implementation for use in testing. It implements the minimum
# necessary interface for interacting with the rest of the Net::SSH::Test
# system.
class Socket < StringIO
attr_reader :host, :port
-
+
# The Net::SSH::Test::Script object in use by this socket. This is the
# canonical script instance that should be used for any test depending on
# this socket instance.
attr_reader :script
-
+
# Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
# and seed it with the necessary events to power the initialization of the
# connection.
def initialize
extend(Net::SSH::Transport::PacketStream)
super "SSH-2.0-Test\r\n"
-
+
@script = Script.new
-
+
script.sends(:kexinit)
script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
script.sends(:newkeys)
script.gets(:newkeys)
end
-
+
# This doesn't actually do anything, since we don't really care what gets
# written.
def write(data)
# black hole, because we don't actually care about what gets written
end
-
+
# Allows the socket to also mimic a socket factory, simply returning
# +self+.
- def open(host, port, options={})
+ def open(host, port, options = {})
@host, @port = host, port
self
end
-
+
# Returns a sockaddr struct for the port and host that were used when the
# socket was instantiated.
def getpeername
::Socket.sockaddr_in(port, host)
end
-
+
# Alias to #read, but never returns nil (returns an empty string instead).
def recv(n)
read(n) || ""
end
-
+
def readpartial(n)
recv(n)
end
-
end
-
end
end
end
diff --git a/lib/net/ssh/transport/algorithms.rb b/lib/net/ssh/transport/algorithms.rb
index 8126aa6..cc12d95 100644
--- a/lib/net/ssh/transport/algorithms.rb
+++ b/lib/net/ssh/transport/algorithms.rb
@@ -33,12 +33,15 @@ module Net
ecdsa-sha2-nistp256
ssh-rsa-cert-v01@openssh.com
ssh-rsa-cert-v00@openssh.com
- ssh-rsa],
+ ssh-rsa
+ rsa-sha2-256
+ rsa-sha2-512],
kex: %w[ecdh-sha2-nistp521
ecdh-sha2-nistp384
ecdh-sha2-nistp256
diffie-hellman-group-exchange-sha256
+ diffie-hellman-group14-sha256
diffie-hellman-group14-sha1],
encryption: %w[aes256-ctr aes192-ctr aes128-ctr],
@@ -143,7 +146,7 @@ module Net
# Instantiates a new Algorithms object, and prepares the hash of preferred
# algorithms based on the options parameter and the ALGORITHMS constant.
- def initialize(session, options={})
+ def initialize(session, options = {})
@session = session
@logger = session.logger
@options = options
@@ -275,7 +278,7 @@ module Net
# existing known key for the host has preference.
existing_keys = session.host_keys
- host_keys = existing_keys.map { |key| key.ssh_type }.uniq
+ host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
algorithms[:host_key].each do |name|
host_keys << name unless host_keys.include?(name)
end
@@ -366,10 +369,10 @@ module Net
language = algorithms[:language].join(",")
Net::SSH::Buffer.from(:byte, KEXINIT,
- :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
- :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
- :mstring, [compression, compression, language, language],
- :bool, false, :long, 0)
+ :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
+ :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
+ :mstring, [compression, compression, language, language],
+ :bool, false, :long, 0)
end
# Given the parsed server KEX packet, and the client's preferred algorithm
@@ -435,13 +438,13 @@ module Net
debug { "exchanging keys" }
algorithm = Kex::MAP[kex].new(self, session,
- client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
- server_version_string: session.server_version.version,
- server_algorithm_packet: @server_packet,
- client_algorithm_packet: @client_packet,
- need_bytes: kex_byte_requirement,
- minimum_dh_bits: options[:minimum_dh_bits],
- logger: logger)
+ client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
+ server_version_string: session.server_version.version,
+ server_algorithm_packet: @server_packet,
+ client_algorithm_packet: @client_packet,
+ need_bytes: kex_byte_requirement,
+ minimum_dh_bits: options[:minimum_dh_bits],
+ logger: logger)
result = algorithm.exchange_keys
secret = result[:shared_secret].to_ssh
diff --git a/lib/net/ssh/transport/cipher_factory.rb b/lib/net/ssh/transport/cipher_factory.rb
index 13852f3..4dde239 100644
--- a/lib/net/ssh/transport/cipher_factory.rb
+++ b/lib/net/ssh/transport/cipher_factory.rb
@@ -3,31 +3,30 @@ require 'net/ssh/transport/ctr.rb'
require 'net/ssh/transport/key_expander'
require 'net/ssh/transport/identity_cipher'
-module Net
- module SSH
+module Net
+ module SSH
module Transport
-
# Implements a factory of OpenSSL cipher algorithms.
class CipherFactory
# Maps the SSH name of a cipher to it's corresponding OpenSSL name
SSH_TO_OSSL = {
- "3des-cbc" => "des-ede3-cbc",
- "blowfish-cbc" => "bf-cbc",
- "aes256-cbc" => "aes-256-cbc",
- "aes192-cbc" => "aes-192-cbc",
- "aes128-cbc" => "aes-128-cbc",
- "idea-cbc" => "idea-cbc",
- "cast128-cbc" => "cast-cbc",
+ "3des-cbc" => "des-ede3-cbc",
+ "blowfish-cbc" => "bf-cbc",
+ "aes256-cbc" => "aes-256-cbc",
+ "aes192-cbc" => "aes-192-cbc",
+ "aes128-cbc" => "aes-128-cbc",
+ "idea-cbc" => "idea-cbc",
+ "cast128-cbc" => "cast-cbc",
"rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
- "3des-ctr" => "des-ede3",
- "blowfish-ctr" => "bf-ecb",
+ "3des-ctr" => "des-ede3",
+ "blowfish-ctr" => "bf-ecb",
- 'aes256-ctr' => 'aes-256-ctr',
- 'aes192-ctr' => 'aes-192-ctr',
- 'aes128-ctr' => 'aes-128-ctr',
- 'cast128-ctr' => 'cast5-ecb',
+ "aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
+ "aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
+ "aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
+ 'cast128-ctr' => 'cast5-ecb',
- 'none' => 'none'
+ 'none' => 'none'
}
# Returns true if the underlying OpenSSL library supports the given cipher,
@@ -35,23 +34,25 @@ module Net
def self.supported?(name)
ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
return true if ossl_name == "none"
+
return OpenSSL::Cipher.ciphers.include?(ossl_name)
end
-
+
# Retrieves a new instance of the named algorithm. The new instance
# will be initialized using an iv and key generated from the given
# iv, key, shared, hash and digester values. Additionally, the
# cipher will be put into encryption or decryption mode, based on the
# value of the +encrypt+ parameter.
- def self.get(name, options={})
+ def self.get(name, options = {})
ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
return IdentityCipher if ossl_name == "none"
+
cipher = OpenSSL::Cipher.new(ossl_name)
-
+
cipher.send(options[:encrypt] ? :encrypt : :decrypt)
-
+
cipher.padding = 0
-
+
if name =~ /-ctr(@openssh.org)?$/
if ossl_name !~ /-ctr/
cipher.extend(Net::SSH::Transport::CTR)
@@ -60,14 +61,14 @@ module Net
end
end
cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)
-
+
key_len = cipher.key_len
cipher.key_len = key_len
cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
-
+
return cipher
end
-
+
# Returns a two-element array containing the [ key-length,
# block-size ] for the named cipher algorithm. If the cipher
# algorithm is unknown, or is "none", 0 is returned for both elements
@@ -82,7 +83,7 @@ module Net
cipher = OpenSSL::Cipher.new(ossl_name)
key_len = cipher.key_len
cipher.key_len = key_len
-
+
block_size =
case ossl_name
when /\-ctr/
@@ -90,14 +91,13 @@ module Net
else
cipher.block_size
end
-
+
result = [key_len, block_size]
result << cipher.iv_len if options[:iv_len]
end
result
end
end
-
end
end
end
diff --git a/lib/net/ssh/transport/constants.rb b/lib/net/ssh/transport/constants.rb
index 26747a6..b3c5fb4 100644
--- a/lib/net/ssh/transport/constants.rb
+++ b/lib/net/ssh/transport/constants.rb
@@ -1,5 +1,5 @@
-module Net
- module SSH
+module Net
+ module SSH
module Transport
module Constants
#--
@@ -12,7 +12,7 @@ module Net
DEBUG = 4
SERVICE_REQUEST = 5
SERVICE_ACCEPT = 6
-
+
#--
# Algorithm negotiation messages
#++
diff --git a/lib/net/ssh/transport/ctr.rb b/lib/net/ssh/transport/ctr.rb
index d952a86..a1397f4 100644
--- a/lib/net/ssh/transport/ctr.rb
+++ b/lib/net/ssh/transport/ctr.rb
@@ -2,7 +2,7 @@ require 'openssl'
require 'delegate'
module Net::SSH::Transport
- #:nodoc:
+ # :nodoc:
class OpenSSLAESCTR < SimpleDelegator
def initialize(original)
super
@@ -26,13 +26,13 @@ module Net::SSH::Transport
end
end
- #:nodoc:
+ # :nodoc:
# Pure-Ruby implementation of Stateful Decryption Counter(SDCTR) Mode
# for Block Ciphers. See RFC4344 for detail.
module CTR
def self.extended(orig)
orig.instance_eval {
- @remaining = ""
+ @remaining = String.new
@counter = nil
@counter_len = orig.block_size
orig.encrypt
@@ -67,13 +67,13 @@ module Net::SSH::Transport
end
def reset
- @remaining = ""
+ @remaining = String.new
end
def update(data)
@remaining += data
- encrypted = ""
+ encrypted = String.new
offset = 0
while (@remaining.bytesize - offset) >= block_size
@@ -89,13 +89,13 @@ module Net::SSH::Transport
def final
s = @remaining.empty? ? '' : xor!(@remaining, _update(@counter))
- @remaining = ""
+ @remaining = String.new
s
end
def xor!(s1, s2)
s = []
- s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a ^ b) }
+ s1.unpack('Q*').zip(s2.unpack('Q*')) {|a, b| s.push(a ^ b) }
s.pack('Q*')
end
singleton_class.send(:private, :xor!)
diff --git a/lib/net/ssh/transport/hmac.rb b/lib/net/ssh/transport/hmac.rb
index 0905050..0742236 100644
--- a/lib/net/ssh/transport/hmac.rb
+++ b/lib/net/ssh/transport/hmac.rb
@@ -17,24 +17,24 @@ require 'net/ssh/transport/hmac/none'
module Net::SSH::Transport::HMAC
# The mapping of SSH hmac algorithms to their implementations
MAP = {
- 'hmac-md5' => MD5,
- 'hmac-md5-96' => MD5_96,
- 'hmac-sha1' => SHA1,
- 'hmac-sha1-96' => SHA1_96,
- 'hmac-sha2-256' => SHA2_256,
- 'hmac-sha2-256-96' => SHA2_256_96,
- 'hmac-sha2-512' => SHA2_512,
- 'hmac-sha2-512-96' => SHA2_512_96,
+ 'hmac-md5' => MD5,
+ 'hmac-md5-96' => MD5_96,
+ 'hmac-sha1' => SHA1,
+ 'hmac-sha1-96' => SHA1_96,
+ 'hmac-sha2-256' => SHA2_256,
+ 'hmac-sha2-256-96' => SHA2_256_96,
+ 'hmac-sha2-512' => SHA2_512,
+ 'hmac-sha2-512-96' => SHA2_512_96,
'hmac-sha2-256-etm@openssh.com' => SHA2_256_Etm,
'hmac-sha2-512-etm@openssh.com' => SHA2_512_Etm,
- 'hmac-ripemd160' => RIPEMD160,
- 'hmac-ripemd160@openssh.com' => RIPEMD160,
- 'none' => None
+ 'hmac-ripemd160' => RIPEMD160,
+ 'hmac-ripemd160@openssh.com' => RIPEMD160,
+ 'none' => None
}
# Retrieves a new hmac instance of the given SSH type (+name+). If +key+ is
# given, the new instance will be initialized with that key.
- def self.get(name, key="", parameters = {})
+ def self.get(name, key = "", parameters = {})
impl = MAP[name] or raise ArgumentError, "hmac not found: #{name.inspect}"
impl.new(Net::SSH::Transport::KeyExpander.expand_key(impl.key_length, key, parameters))
end
diff --git a/lib/net/ssh/transport/hmac/abstract.rb b/lib/net/ssh/transport/hmac/abstract.rb
index f8efa3e..8bc2a56 100644
--- a/lib/net/ssh/transport/hmac/abstract.rb
+++ b/lib/net/ssh/transport/hmac/abstract.rb
@@ -5,10 +5,9 @@ module Net
module SSH
module Transport
module HMAC
-
# The base class of all OpenSSL-based HMAC algorithm wrappers.
class Abstract
- class <<self
+ class << self
def etm(*v)
@etm = false if !defined?(@etm)
if v.empty?
@@ -77,19 +76,19 @@ module Net
# The key in use for this instance.
attr_reader :key
- def initialize(key=nil)
+ def initialize(key = nil)
self.key = key
end
# Sets the key to the given value, truncating it so that it is the correct
# length.
def key=(value)
- @key = value ? value.to_s[0,key_length] : nil
+ @key = value ? value.to_s[0, key_length] : nil
end
# Compute the HMAC digest for the given data string.
def digest(data)
- OpenSSL::HMAC.digest(digest_class.new, key, data)[0,mac_length]
+ OpenSSL::HMAC.digest(digest_class.new, key, data)[0, mac_length]
end
end
end
diff --git a/lib/net/ssh/transport/hmac/md5.rb b/lib/net/ssh/transport/hmac/md5.rb
index 66b78ca..549b1aa 100644
--- a/lib/net/ssh/transport/hmac/md5.rb
+++ b/lib/net/ssh/transport/hmac/md5.rb
@@ -1,12 +1,10 @@
require 'net/ssh/transport/hmac/abstract'
module Net::SSH::Transport::HMAC
-
# The MD5 HMAC algorithm.
class MD5 < Abstract
mac_length 16
key_length 16
digest_class OpenSSL::Digest::MD5
end
-
end
diff --git a/lib/net/ssh/transport/hmac/md5_96.rb b/lib/net/ssh/transport/hmac/md5_96.rb
index 826b70a..6dbebc1 100644
--- a/lib/net/ssh/transport/hmac/md5_96.rb
+++ b/lib/net/ssh/transport/hmac/md5_96.rb
@@ -1,11 +1,9 @@
require 'net/ssh/transport/hmac/md5'
module Net::SSH::Transport::HMAC
-
# The MD5-96 HMAC algorithm. This returns only the first 12 bytes of
# the digest.
class MD5_96 < MD5
mac_length 12
end
-
end
diff --git a/lib/net/ssh/transport/hmac/none.rb b/lib/net/ssh/transport/hmac/none.rb
index 191373e..a5e3af4 100644
--- a/lib/net/ssh/transport/hmac/none.rb
+++ b/lib/net/ssh/transport/hmac/none.rb
@@ -1,7 +1,6 @@
require 'net/ssh/transport/hmac/abstract'
module Net::SSH::Transport::HMAC
-
# The "none" algorithm. This has a key and mac length of 0.
class None < Abstract
key_length 0
@@ -11,5 +10,4 @@ module Net::SSH::Transport::HMAC
""
end
end
-
end
diff --git a/lib/net/ssh/transport/hmac/ripemd160.rb b/lib/net/ssh/transport/hmac/ripemd160.rb
index a77e4cd..4c9cdd7 100644
--- a/lib/net/ssh/transport/hmac/ripemd160.rb
+++ b/lib/net/ssh/transport/hmac/ripemd160.rb
@@ -1,7 +1,6 @@
require 'net/ssh/transport/hmac/abstract'
module Net::SSH::Transport::HMAC
-
# The RIPEMD-160 HMAC algorithm. This has a mac and key length of 20, and
# uses the RIPEMD-160 digest algorithm.
class RIPEMD160 < Abstract
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
key_length 20
digest_class OpenSSL::Digest::RIPEMD160
end
-
end
diff --git a/lib/net/ssh/transport/hmac/sha1.rb b/lib/net/ssh/transport/hmac/sha1.rb
index b40d32f..9208392 100644
--- a/lib/net/ssh/transport/hmac/sha1.rb
+++ b/lib/net/ssh/transport/hmac/sha1.rb
@@ -1,7 +1,6 @@
require 'net/ssh/transport/hmac/abstract'
module Net::SSH::Transport::HMAC
-
# The SHA1 HMAC algorithm. This has a mac and key length of 20, and
# uses the SHA1 digest algorithm.
class SHA1 < Abstract
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
key_length 20
digest_class OpenSSL::Digest::SHA1
end
-
end
diff --git a/lib/net/ssh/transport/hmac/sha1_96.rb b/lib/net/ssh/transport/hmac/sha1_96.rb
index 6b0b3c2..e1631e7 100644
--- a/lib/net/ssh/transport/hmac/sha1_96.rb
+++ b/lib/net/ssh/transport/hmac/sha1_96.rb
@@ -1,11 +1,9 @@
require 'net/ssh/transport/hmac/sha1'
module Net::SSH::Transport::HMAC
-
# The SHA1-96 HMAC algorithm. This returns only the first 12 bytes of
# the digest.
class SHA1_96 < SHA1
mac_length 12
end
-
end
diff --git a/lib/net/ssh/transport/identity_cipher.rb b/lib/net/ssh/transport/identity_cipher.rb
index c690e9f..ad1a764 100644
--- a/lib/net/ssh/transport/identity_cipher.rb
+++ b/lib/net/ssh/transport/identity_cipher.rb
@@ -1,59 +1,57 @@
-module Net
- module SSH
+module Net
+ module SSH
module Transport
-
# A cipher that does nothing but pass the data through, unchanged. This
# keeps things in the code nice and clean when a cipher has not yet been
# determined (i.e., during key exchange).
class IdentityCipher
- class <<self
+ class << self
# A default block size of 8 is required by the SSH2 protocol.
def block_size
8
end
-
+
# Returns an arbitrary integer.
def iv_len
4
end
-
+
# Does nothing. Returns self.
def encrypt
self
end
-
+
# Does nothing. Returns self.
def decrypt
self
end
-
+
# Passes its single argument through unchanged.
def update(text)
text
end
-
+
# Returns the empty string.
def final
""
end
-
+
# The name of this cipher, which is "identity".
def name
"identity"
end
-
+
# Does nothing. Returns nil.
def iv=(v)
nil
end
-
+
# Does nothing. Returns self.
def reset
self
end
end
end
-
end
end
end
diff --git a/lib/net/ssh/transport/kex.rb b/lib/net/ssh/transport/kex.rb
index b3571c3..cf21107 100644
--- a/lib/net/ssh/transport/kex.rb
+++ b/lib/net/ssh/transport/kex.rb
@@ -1,5 +1,6 @@
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
+require 'net/ssh/transport/kex/diffie_hellman_group14_sha256'
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha256'
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
@@ -12,13 +13,14 @@ module Net::SSH::Transport
# Maps the supported key-exchange algorithms as named by the SSH protocol
# to their corresponding implementors.
MAP = {
- 'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1,
- 'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
- 'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1,
+ 'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1,
+ 'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
+ 'diffie-hellman-group14-sha256' => DiffieHellmanGroup14SHA256,
+ 'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1,
'diffie-hellman-group-exchange-sha256' => DiffieHellmanGroupExchangeSHA256,
- 'ecdh-sha2-nistp256' => EcdhSHA2NistP256,
- 'ecdh-sha2-nistp384' => EcdhSHA2NistP384,
- 'ecdh-sha2-nistp521' => EcdhSHA2NistP521
+ 'ecdh-sha2-nistp256' => EcdhSHA2NistP256,
+ 'ecdh-sha2-nistp384' => EcdhSHA2NistP384,
+ 'ecdh-sha2-nistp521' => EcdhSHA2NistP521
}
if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
diff --git a/lib/net/ssh/transport/kex/abstract.rb b/lib/net/ssh/transport/kex/abstract.rb
index c70eb94..27d2613 100644
--- a/lib/net/ssh/transport/kex/abstract.rb
+++ b/lib/net/ssh/transport/kex/abstract.rb
@@ -64,11 +64,16 @@ module Net
private
+ def matching?(key_ssh_type, host_key_alg)
+ return true if key_ssh_type == host_key_alg
+ return true if key_ssh_type == 'ssh-rsa' && ['rsa-sha2-512', 'rsa-sha2-256'].include?(host_key_alg)
+ end
+
# Verify that the given key is of the expected type, and that it
# really is the key for the session's host. Raise Net::SSH::Exception
# if it is not.
- def verify_server_key(key) #:nodoc:
- if key.ssh_type != algorithms.host_key
+ def verify_server_key(key) # :nodoc:
+ unless matching?(key.ssh_type, algorithms.host_key)
raise Net::SSH::Exception, "host key algorithm mismatch '#{key.ssh_type}' != '#{algorithms.host_key}'"
end
@@ -92,12 +97,14 @@ module Net
# Verify the signature that was received. Raise Net::SSH::Exception
# if the signature could not be verified. Otherwise, return the new
# session-id.
- def verify_signature(result) #:nodoc:
+ def verify_signature(result) # :nodoc:
response = build_signature_buffer(result)
hash = digester.digest(response.to_s)
- unless connection.host_key_verifier.verify_signature { result[:server_key].ssh_do_verify(result[:server_sig], hash) }
+ server_key = result[:server_key]
+ server_sig = result[:server_sig]
+ unless connection.host_key_verifier.verify_signature { server_key.ssh_do_verify(server_sig, hash, host_key: algorithms.host_key) }
raise Net::SSH::Exception, 'could not verify server signature'
end
@@ -106,7 +113,7 @@ module Net
# Send the NEWKEYS message, and expect the NEWKEYS message in
# reply.
- def confirm_newkeys #:nodoc:
+ def confirm_newkeys # :nodoc:
# send own NEWKEYS message first (the wodSSHServer won't send first)
response = Net::SSH::Buffer.new
response.write_byte(NEWKEYS)
diff --git a/lib/net/ssh/transport/kex/abstract5656.rb b/lib/net/ssh/transport/kex/abstract5656.rb
index 06c874d..5f8d133 100644
--- a/lib/net/ssh/transport/kex/abstract5656.rb
+++ b/lib/net/ssh/transport/kex/abstract5656.rb
@@ -32,7 +32,7 @@ module Net
response
end
- def send_kexinit #:nodoc:
+ def send_kexinit # :nodoc:
init, reply = get_message_types
# send the KEXECDH_INIT message
diff --git a/lib/net/ssh/transport/kex/curve25519_sha256.rb b/lib/net/ssh/transport/kex/curve25519_sha256.rb
index 9aeba85..e942846 100644
--- a/lib/net/ssh/transport/kex/curve25519_sha256.rb
+++ b/lib/net/ssh/transport/kex/curve25519_sha256.rb
@@ -1,6 +1,7 @@
gem 'x25519' # raise if the gem x25519 is not installed
require 'x25519'
+
require 'net/ssh/transport/constants'
require 'net/ssh/transport/kex/abstract5656'
@@ -17,7 +18,7 @@ module Net
private
- def generate_key #:nodoc:
+ def generate_key # :nodoc:
::X25519::Scalar.generate
end
diff --git a/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb b/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb
index d560da8..d74c521 100644
--- a/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb
+++ b/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb
@@ -1,8 +1,8 @@
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
-module Net
- module SSH
- module Transport
+module Net
+ module SSH
+ module Transport
module Kex
# A key-exchange service implementing the "diffie-hellman-group14-sha1"
# key-exchange algorithm. (defined in RFC 4253)
@@ -24,7 +24,7 @@ module Net
"B5C55DF0" "6F4C52C9" "DE2BCBF6" "95581718" +
"3995497C" "EA956AE5" "15D22618" "98FA0510" +
"15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"
-
+
# The radix in which P_s represents the value of P
P_r = 16
diff --git a/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb b/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb
new file mode 100644
index 0000000..7fd985a
--- /dev/null
+++ b/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb
@@ -0,0 +1,11 @@
+require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
+
+module Net::SSH::Transport::Kex
+ # A key-exchange service implementing the "diffie-hellman-group14-sha256"
+ # key-exchange algorithm.
+ class DiffieHellmanGroup14SHA256 < DiffieHellmanGroup14SHA1
+ def digester
+ OpenSSL::Digest::SHA256
+ end
+ end
+end
diff --git a/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb b/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
index 34af18b..9abab2c 100644
--- a/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
+++ b/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
@@ -59,7 +59,7 @@ module Net
# Generate a DH key with a private key consisting of the given
# number of bytes.
- def generate_key #:nodoc:
+ def generate_key # :nodoc:
dh = OpenSSL::PKey::DH.new
if dh.respond_to?(:set_pqg)
@@ -86,7 +86,7 @@ module Net
#
# Parse the buffer from a KEXDH_REPLY message, returning a hash of
# the extracted values.
- def send_kexinit #:nodoc:
+ def send_kexinit # :nodoc:
init, reply = get_message_types
# send the KEXDH_INIT message
@@ -108,8 +108,8 @@ module Net
sig_type = sig_buffer.read_string
if sig_type != algorithms.host_key_format
raise Net::SSH::Exception,
- "host key algorithm mismatch for signature " +
- "'#{sig_type}' != '#{algorithms.host_key_format}'"
+ "host key algorithm mismatch for signature " +
+ "'#{sig_type}' != '#{algorithms.host_key_format}'"
end
result[:server_sig] = sig_buffer.read_string
diff --git a/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb b/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb
index bd5e4a9..22178e2 100644
--- a/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb
+++ b/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb
@@ -34,7 +34,7 @@ module Net::SSH::Transport::Kex
# request the DH key parameters for the given number of bits.
buffer = Net::SSH::Buffer.from(:byte, KEXDH_GEX_REQUEST, :long, data[:minimum_dh_bits],
- :long, data[:need_bits], :long, MAXIMUM_BITS)
+ :long, data[:need_bits], :long, MAXIMUM_BITS)
connection.send_message(buffer)
buffer = connection.next_message
@@ -69,5 +69,4 @@ module Net::SSH::Transport::Kex
response
end
end
-
end
diff --git a/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb b/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
index 84d0e4a..a0c911d 100644
--- a/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
+++ b/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
@@ -17,7 +17,7 @@ module Net
private
- def generate_key #:nodoc:
+ def generate_key # :nodoc:
OpenSSL::PKey::EC.new(curve_name).generate_key
end
diff --git a/lib/net/ssh/transport/key_expander.rb b/lib/net/ssh/transport/key_expander.rb
index 108e9b9..8cff7e9 100644
--- a/lib/net/ssh/transport/key_expander.rb
+++ b/lib/net/ssh/transport/key_expander.rb
@@ -1,28 +1,27 @@
-module Net
- module SSH
+module Net
+ module SSH
module Transport
module KeyExpander
-
# Generate a key value in accordance with the SSH2 specification.
# (RFC4253 7.2. "Output from Key Exchange")
- def self.expand_key(bytes, start, options={})
+ def self.expand_key(bytes, start, options = {})
if bytes == 0
return ""
end
-
+
k = start[0, bytes]
return k if k.length >= bytes
-
+
digester = options[:digester] or raise 'No digester supplied'
shared = options[:shared] or raise 'No shared secret supplied'
hash = options[:hash] or raise 'No hash supplied'
-
+
while k.length < bytes
step = digester.digest(shared + hash + k)
bytes_needed = bytes - k.length
k << step[0, bytes_needed]
end
-
+
return k
end
end
diff --git a/lib/net/ssh/transport/openssl.rb b/lib/net/ssh/transport/openssl.rb
index d2d7117..1c23651 100644
--- a/lib/net/ssh/transport/openssl.rb
+++ b/lib/net/ssh/transport/openssl.rb
@@ -2,7 +2,6 @@ require 'openssl'
require 'net/ssh/authentication/pub_key_fingerprint'
module OpenSSL
-
# This class is originally defined in the OpenSSL module. As needed, methods
# have been added to it by the Net::SSH module for convenience in dealing with
# SSH functionality.
@@ -24,7 +23,6 @@ module OpenSSL
end
module PKey
-
class PKey
include Net::SSH::Authentication::PubKeyFingerprint
end
@@ -37,6 +35,7 @@ module OpenSSL
# lifted more-or-less directly from OpenSSH, dh.c, dh_pub_is_valid.)
def valid?
return false if pub_key.nil? || pub_key < 0
+
bits_set = 0
pub_key.num_bits.times { |i| bits_set += 1 if pub_key.bit_set?(i) }
return (bits_set > 1 && pub_key < p)
@@ -53,9 +52,7 @@ module OpenSSL
"ssh-rsa"
end
- def ssh_signature_type
- ssh_type
- end
+ alias ssh_signature_type ssh_type
# Converts the key to a blob, according to the SSH2 protocol.
def to_blob
@@ -63,13 +60,30 @@ module OpenSSL
end
# Verifies the given signature matches the given data.
- def ssh_do_verify(sig, data)
- verify(OpenSSL::Digest::SHA1.new, sig, data)
+ def ssh_do_verify(sig, data, options = {})
+ digester =
+ if options[:host_key] == "rsa-sha2-512"
+ OpenSSL::Digest::SHA512.new
+ elsif options[:host_key] == "rsa-sha2-256"
+ OpenSSL::Digest::SHA256.new
+ else
+ OpenSSL::Digest::SHA1.new
+ end
+
+ verify(digester, sig, data)
end
# Returns the signature for the given data.
- def ssh_do_sign(data)
- sign(OpenSSL::Digest::SHA1.new, data)
+ def ssh_do_sign(data, sig_alg = nil)
+ digester =
+ if sig_alg == "rsa-sha2-512"
+ OpenSSL::Digest::SHA512.new
+ elsif sig_alg == "rsa-sha2-256"
+ OpenSSL::Digest::SHA256.new
+ else
+ OpenSSL::Digest::SHA1.new
+ end
+ sign(digester, data)
end
end
@@ -83,20 +97,18 @@ module OpenSSL
"ssh-dss"
end
- def ssh_signature_type
- ssh_type
- end
+ alias ssh_signature_type ssh_type
# Converts the key to a blob, according to the SSH2 protocol.
def to_blob
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
- :bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
+ :bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
end
# Verifies the given signature matches the given data.
- def ssh_do_verify(sig, data)
- sig_r = sig[0,20].unpack("H*")[0].to_i(16)
- sig_s = sig[20,20].unpack("H*")[0].to_i(16)
+ def ssh_do_verify(sig, data, options = {})
+ sig_r = sig[0, 20].unpack("H*")[0].to_i(16)
+ sig_s = sig[20, 20].unpack("H*")[0].to_i(16)
a1sig = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(sig_r),
OpenSSL::ASN1::Integer(sig_s)
@@ -105,7 +117,7 @@ module OpenSSL
end
# Signs the given data.
- def ssh_do_sign(data)
+ def ssh_do_sign(data, sig_alg = nil)
sig = sign(OpenSSL::Digest::SHA1.new, data)
a1sig = OpenSSL::ASN1.decode(sig)
@@ -163,9 +175,7 @@ module OpenSSL
"ecdsa-sha2-#{CurveNameAliasInv[group.curve_name]}"
end
- def ssh_signature_type
- ssh_type
- end
+ alias ssh_signature_type ssh_type
def digester
if group.curve_name =~ /^[a-z]+(\d+)\w*\z/
@@ -192,7 +202,7 @@ module OpenSSL
end
# Verifies the given signature matches the given data.
- def ssh_do_verify(sig, data)
+ def ssh_do_verify(sig, data, options = {})
digest = digester.digest(data)
a1sig = nil
@@ -218,7 +228,7 @@ module OpenSSL
end
# Returns the signature for the given data.
- def ssh_do_sign(data)
+ def ssh_do_sign(data, sig_alg = nil)
digest = digester.digest(data)
sig = dsa_sign_asn1(digest)
a1sig = OpenSSL::ASN1.decode(sig)
@@ -236,6 +246,8 @@ module OpenSSL
"ecdsa-sha2-#{CurveNameAliasInv[group.curve_name]}"
end
+ alias ssh_signature_type ssh_type
+
# Converts the key to a blob, according to the SSH2 protocol.
def to_blob
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
diff --git a/lib/net/ssh/transport/packet_stream.rb b/lib/net/ssh/transport/packet_stream.rb
index 8b4032e..a4120d4 100644
--- a/lib/net/ssh/transport/packet_stream.rb
+++ b/lib/net/ssh/transport/packet_stream.rb
@@ -8,7 +8,6 @@ require 'net/ssh/transport/state'
module Net
module SSH
module Transport
-
# A module that builds additional functionality onto the Net::SSH::BufferedIo
# module. It adds SSH encryption, compression, and packet validation, as
# per the SSH2 protocol. It also adds an abstraction for polling packets,
@@ -81,7 +80,7 @@ module Net
# available or not, and will return nil if there is no packet ready to be
# returned. If the mode parameter is :block, then this method will block
# until a packet is available or timeout seconds have passed.
- def next_packet(mode=:nonblock, timeout=nil)
+ def next_packet(mode = :nonblock, timeout = nil)
case mode
when :nonblock then
packet = poll_next_packet
@@ -222,6 +221,7 @@ module Net
if @packet.nil?
minimum = server.block_size < 4 ? 4 : server.block_size
return nil if available < minimum + aad_length
+
data = read_available(minimum + aad_length)
# decipher it
@@ -275,7 +275,6 @@ module Net
end
end
# rubocop:enable Metrics/AbcSize
-
end
end
end
diff --git a/lib/net/ssh/transport/server_version.rb b/lib/net/ssh/transport/server_version.rb
index 1012685..50ffb15 100644
--- a/lib/net/ssh/transport/server_version.rb
+++ b/lib/net/ssh/transport/server_version.rb
@@ -2,10 +2,9 @@ require 'net/ssh/errors'
require 'net/ssh/loggable'
require 'net/ssh/version'
-module Net
- module SSH
+module Net
+ module SSH
module Transport
-
# Negotiates the SSH protocol version and trades information about server
# and client. This is never used directly--it is always called by the
# transport layer as part of the initialization process of the transport
@@ -15,40 +14,41 @@ module Net
# the authoritative reference for any queries regarding the version in effect.
class ServerVersion
include Loggable
-
+
# The SSH version string as reported by Net::SSH
PROTO_VERSION = "SSH-2.0-Ruby/Net::SSH_#{Net::SSH::Version::CURRENT} #{RUBY_PLATFORM}"
-
+
# Any header text sent by the server prior to sending the version.
attr_reader :header
-
+
# The version string reported by the server.
attr_reader :version
-
+
# Instantiates a new ServerVersion and immediately (and synchronously)
# negotiates the SSH protocol in effect, using the given socket.
def initialize(socket, logger, timeout = nil)
- @header = ""
+ @header = String.new
@version = nil
@logger = logger
negotiate!(socket, timeout)
end
-
+
private
-
+
# Negotiates the SSH protocol to use, via the given socket. If the server
# reports an incompatible SSH version (e.g., SSH1), this will raise an
# exception.
def negotiate!(socket, timeout)
info { "negotiating protocol version" }
-
+
debug { "local is `#{PROTO_VERSION}'" }
socket.write "#{PROTO_VERSION}\r\n"
socket.flush
-
+
raise Net::SSH::ConnectionTimeout, "timeout during server version negotiating" if timeout && !IO.select([socket], nil, nil, timeout)
+
loop do
- @version = ""
+ @version = String.new
loop do
begin
b = socket.readpartial(1)
@@ -60,14 +60,15 @@ module Net
break if b == "\n"
end
break if @version.match(/^SSH-/)
+
@header << @version
end
-
+
@version.chomp!
debug { "remote is `#{@version}'" }
-
+
raise Net::SSH::Exception, "incompatible SSH version `#{@version}'" unless @version.match(/^SSH-(1\.99|2\.0)-/)
-
+
raise Net::SSH::ConnectionTimeout, "timeout during client version negotiating" if timeout && !IO.select(nil, [socket], nil, timeout)
end
end
diff --git a/lib/net/ssh/transport/session.rb b/lib/net/ssh/transport/session.rb
index ce55a32..fb41c16 100644
--- a/lib/net/ssh/transport/session.rb
+++ b/lib/net/ssh/transport/session.rb
@@ -15,7 +15,6 @@ require 'net/ssh/verifiers/never'
module Net
module SSH
module Transport
-
# The transport layer represents the lowest level of the SSH protocol, and
# implements basic message exchanging and protocol initialization. It will
# never be instantiated directly (unless you really know what you're about),
@@ -56,7 +55,7 @@ module Net
# Instantiates a new transport layer abstraction. This will block until
# the initial key exchange completes, leaving you with a ready-to-use
# transport session.
- def initialize(host, options={})
+ def initialize(host, options = {})
self.logger = options[:logger]
@host = host
@@ -160,6 +159,7 @@ module Net
# one is performed, causing this method to block until it completes.
def rekey_as_needed
return if algorithms.pending?
+
socket.if_needs_rekey? { rekey! }
end
@@ -186,7 +186,7 @@ module Net
# received, it will be enqueued and otherwise ignored. When a key-exchange
# is not in process, and consume_queue is true, packets will be first
# read from the queue before the socket is queried.
- def poll_message(mode=:nonblock, consume_queue=true)
+ def poll_message(mode = :nonblock, consume_queue = true)
loop do
return @queue.shift if consume_queue && @queue.any? && algorithms.allow?(@queue.first)
@@ -211,6 +211,7 @@ module Net
else
return packet if algorithms.allow?(packet)
+
push(packet)
end
end
@@ -222,6 +223,7 @@ module Net
def wait
loop do
break if block_given? && yield
+
message = poll_message(:nonblock, false)
push(message) if message
break if !block_given?
@@ -250,27 +252,27 @@ module Net
# Configure's the packet stream's client state with the given set of
# options. This is typically used to define the cipher, compression, and
# hmac algorithms to use when sending packets to the server.
- def configure_client(options={})
+ def configure_client(options = {})
socket.client.set(options)
end
# Configure's the packet stream's server state with the given set of
# options. This is typically used to define the cipher, compression, and
# hmac algorithms to use when reading packets from the server.
- def configure_server(options={})
+ def configure_server(options = {})
socket.server.set(options)
end
# Sets a new hint for the packet stream, which the packet stream may use
# to change its behavior. (See PacketStream#hints).
- def hint(which, value=true)
+ def hint(which, value = true)
socket.hints[which] = value
end
public
# this method is primarily for use in tests
- attr_reader :queue #:nodoc:
+ attr_reader :queue # :nodoc:
private
diff --git a/lib/net/ssh/transport/state.rb b/lib/net/ssh/transport/state.rb
index 07c509a..1af6b86 100644
--- a/lib/net/ssh/transport/state.rb
+++ b/lib/net/ssh/transport/state.rb
@@ -2,10 +2,9 @@ require 'zlib'
require 'net/ssh/transport/cipher_factory'
require 'net/ssh/transport/hmac'
-module Net
- module SSH
+module Net
+ module SSH
module Transport
-
# Encapsulates state information about one end of an SSH connection. Such
# state includes the packet sequence number, the algorithms in use, how
# many packets and blocks have been processed since the last reset, and so
@@ -14,46 +13,46 @@ module Net
class State
# The socket object that owns this state object.
attr_reader :socket
-
+
# The next packet sequence number for this socket endpoint.
attr_reader :sequence_number
-
+
# The hmac algorithm in use for this endpoint.
attr_reader :hmac
-
+
# The compression algorithm in use for this endpoint.
attr_reader :compression
-
+
# The compression level to use when compressing data (or nil, for the default).
attr_reader :compression_level
-
+
# The number of packets processed since the last call to #reset!
attr_reader :packets
-
+
# The number of data blocks processed since the last call to #reset!
attr_reader :blocks
-
+
# The cipher algorithm in use for this socket endpoint.
attr_reader :cipher
-
+
# The block size for the cipher
attr_reader :block_size
-
+
# The role that this state plays (either :client or :server)
attr_reader :role
-
+
# The maximum number of packets that this endpoint wants to process before
# needing a rekey.
attr_accessor :max_packets
-
+
# The maximum number of blocks that this endpoint wants to process before
# needing a rekey.
attr_accessor :max_blocks
-
+
# The user-specified maximum number of bytes that this endpoint ought to
# process before needing a rekey.
attr_accessor :rekey_limit
-
+
# Creates a new state object, belonging to the given socket. Initializes
# the algorithms to "none".
def initialize(socket, role)
@@ -65,9 +64,9 @@ module Net
@hmac = HMAC.get("none")
@compression = nil
@compressor = @decompressor = nil
- @next_iv = ""
+ @next_iv = String.new
end
-
+
# A convenience method for quickly setting multiple values in a single
# command.
def set(values)
@@ -76,19 +75,19 @@ module Net
end
reset!
end
-
+
def update_cipher(data)
result = cipher.update(data)
update_next_iv(role == :client ? result : data)
return result
end
-
+
def final_cipher
result = cipher.final
update_next_iv(role == :client ? result : "", true)
return result
end
-
+
# Increments the counters. The sequence number is incremented (and remapped
# so it always fits in a 32-bit integer). The number of packets and blocks
# are also incremented.
@@ -97,18 +96,18 @@ module Net
@packets += 1
@blocks += (packet_length + 4) / @block_size
end
-
+
# The compressor object to use when compressing data. This takes into account
# the desired compression level.
def compressor
@compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
end
-
+
# The decompressor object to use when decompressing data.
def decompressor
@decompressor ||= Zlib::Inflate.new(nil)
end
-
+
# Returns true if data compression/decompression is enabled. This will
# return true if :standard compression is selected, or if :delayed
# compression is selected and the :authenticated hint has been received
@@ -116,33 +115,35 @@ module Net
def compression?
compression == :standard || (compression == :delayed && socket.hints[:authenticated])
end
-
+
# Compresses the data. If no compression is in effect, this will just return
# the data unmodified, otherwise it uses #compressor to compress the data.
def compress(data)
data = data.to_s
return data unless compression?
+
compressor.deflate(data, Zlib::SYNC_FLUSH)
end
-
+
# Deompresses the data. If no compression is in effect, this will just return
# the data unmodified, otherwise it uses #decompressor to decompress the data.
def decompress(data)
data = data.to_s
return data unless compression?
+
decompressor.inflate(data)
end
-
+
# Resets the counters on the state object, but leaves the sequence_number
# unchanged. It also sets defaults for and recomputes the max_packets and
# max_blocks values.
def reset!
@packets = @blocks = 0
-
+
@max_packets ||= 1 << 31
-
+
@block_size = cipher.block_size
-
+
if max_blocks.nil?
# cargo-culted from openssh. the idea is that "the 2^(blocksize*2)
# limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB
@@ -152,16 +153,16 @@ module Net
else
@max_blocks = (1 << 30) / @block_size
end
-
+
# if a limit on the # of bytes has been given, convert that into a
# minimum number of blocks processed.
-
+
@max_blocks = [@max_blocks, rekey_limit / @block_size].min if rekey_limit
end
-
+
cleanup
end
-
+
# Closes any the compressor and/or decompressor objects that have been
# instantiated.
def cleanup
@@ -169,17 +170,17 @@ module Net
@compressor.finish if !@compressor.finished?
@compressor.close
end
-
+
if @decompressor
# we call reset here so that we don't get warnings when we try to
# close the decompressor
@decompressor.reset
@decompressor.close
end
-
+
@compressor = @decompressor = nil
end
-
+
# Returns true if the number of packets processed exceeds the maximum
# number of packets, or if the number of blocks processed exceeds the
# maximum number of blocks.
@@ -187,22 +188,21 @@ module Net
max_packets && packets > max_packets ||
max_blocks && blocks > max_blocks
end
-
+
private
-
- def update_next_iv(data, reset=false)
+
+ def update_next_iv(data, reset = false)
@next_iv << data
@next_iv = @next_iv[@next_iv.size - cipher.iv_len..-1]
-
+
if reset
cipher.reset
cipher.iv = @next_iv
end
-
+
return data
end
end
-
end
end
end
diff --git a/lib/net/ssh/verifiers/accept_new.rb b/lib/net/ssh/verifiers/accept_new.rb
index 677ee75..aa68ff2 100644
--- a/lib/net/ssh/verifiers/accept_new.rb
+++ b/lib/net/ssh/verifiers/accept_new.rb
@@ -5,7 +5,6 @@ require 'net/ssh/verifiers/always'
module Net
module SSH
module Verifiers
-
# Does a strict host verification, looking the server up in the known
# host files to see if a key has already been seen for this server. If this
# server does not appear in any host file, this will silently add the
@@ -29,7 +28,6 @@ module Net
return true
end
end
-
end
end
end
diff --git a/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb b/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb
index d9f8589..198782d 100644
--- a/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb
+++ b/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb
@@ -3,7 +3,6 @@ require 'net/ssh/verifiers/accept_new'
module Net
module SSH
module Verifiers
-
# Basically the same as the AcceptNew verifier, but does not try to actually
# verify a connection if the server is the localhost and the port is a
# nonstandard port number. Those two conditions will typically mean the
@@ -14,6 +13,7 @@ module Net
# returns true. Otherwise, performs the standard strict verification.
def verify(arguments)
return true if tunnelled?(arguments)
+
super
end
@@ -28,7 +28,6 @@ module Net
return ip == "127.0.0.1" || ip == "::1"
end
end
-
end
end
end
diff --git a/lib/net/ssh/verifiers/always.rb b/lib/net/ssh/verifiers/always.rb
index b3ce944..0c86589 100644
--- a/lib/net/ssh/verifiers/always.rb
+++ b/lib/net/ssh/verifiers/always.rb
@@ -4,7 +4,6 @@ require 'net/ssh/known_hosts'
module Net
module SSH
module Verifiers
-
# Does a strict host verification, looking the server up in the known
# host files to see if a key has already been seen for this server. If this
# server does not appear in any host file, an exception will be raised
@@ -22,9 +21,13 @@ module Net
# If we found any matches, check to see that the key type and
# blob also match.
+
found = host_keys.any? do |key|
- key.ssh_type == arguments[:key].ssh_type &&
- key.to_blob == arguments[:key].to_blob
+ if key.respond_to?(:matches_key?)
+ key.matches_key?(arguments[:key])
+ else
+ key.ssh_type == arguments[:key].ssh_type && key.to_blob == arguments[:key].to_blob
+ end
end
# If a match was found, return true. Otherwise, raise an exception
@@ -50,7 +53,6 @@ module Net
raise exception
end
end
-
end
end
end
diff --git a/lib/net/ssh/verifiers/never.rb b/lib/net/ssh/verifiers/never.rb
index 11fac1f..43ec072 100644
--- a/lib/net/ssh/verifiers/never.rb
+++ b/lib/net/ssh/verifiers/never.rb
@@ -1,7 +1,6 @@
module Net
module SSH
module Verifiers
-
# This host key verifier simply allows every key it sees, without
# any verification. This is simple, but very insecure because it
# exposes you to MiTM attacks.
@@ -15,7 +14,6 @@ module Net
true
end
end
-
end
end
end
diff --git a/lib/net/ssh/version.rb b/lib/net/ssh/version.rb
index 662e92e..c7de5f6 100644
--- a/lib/net/ssh/version.rb
+++ b/lib/net/ssh/version.rb
@@ -49,14 +49,14 @@ module Net
MAJOR = 6
# The minor component of this version of the Net::SSH library
- MINOR = 1
+ MINOR = 3
# The tiny component of this version of the Net::SSH library
TINY = 0
# The prerelease component of this version of the Net::SSH library
# nil allowed
- PRE = nil
+ PRE = "beta1"
# The current version of the Net::SSH library as a Version instance
CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact)
diff --git a/net-ssh-public_cert.pem b/net-ssh-public_cert.pem
index 9d06d3d..f51a7a0 100644
--- a/net-ssh-public_cert.pem
+++ b/net-ssh-public_cert.pem
@@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDQDCCAiigAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpuZXRz
-c2gvREM9c29sdXRpb3VzL0RDPWNvbTAeFw0yMDA0MTEwNTQyMTZaFw0yMTA0MTEw
-NTQyMTZaMCUxIzAhBgNVBAMMGm5ldHNzaC9EQz1zb2x1dGlvdXMvREM9Y29tMIIB
+c2gvREM9c29sdXRpb3VzL0RDPWNvbTAeFw0yMTA4MTAwODMyMzBaFw0yMjA4MTAw
+ODMyMzBaMCUxIzAhBgNVBAMMGm5ldHNzaC9EQz1zb2x1dGlvdXMvREM9Y29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxieE22fR/qmdPKUHyYTyUx2g
wskLwrCkxay+Tvc97ZZUOwf85LDDDPqhQaTWLvRwnIOMgQE2nBPzwalVclK6a+pW
x/18KDeZY15vm3Qn5p42b0wi9hUxOqPm3J2hdCLCcgtENgdX21nVzejn39WVqFJO
@@ -11,10 +11,10 @@ fBbmDnsMLAtAtauMOxORrbx3EOY7sHku/kSrMg3FXFay7jc6BkbbUij+MjJ/k82l
AQABo3sweTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUBfKiwO2e
M4NEiRrVG793qEPLYyMwHwYDVR0RBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20w
HwYDVR0SBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20wDQYJKoZIhvcNAQELBQAD
-ggEBAJTylLYXo5AybI+tLq79+OXQ8/nbGZ7iydU1uTHQud1JZQ1MRV5dRDjeBmCT
-lRxaEZT4NopEzuHO0sm3nVpSYtQwTaQyVKmnllNI3kc0f4H6i7dpPd7eUAQ3/O2I
-eWjDJlzu0zwqTa+N6vzS8Y3ypDSGgb1gJKzluOv7viVUAthmuuJws7XQq/qMMaNw
-3163oCKuJvMW1w8kdUMQqvlLJkVKaxz9K64r2+a04Ok1cKloTB3OSowfAYFoRlqP
-voajiJNS75Pw/2j13WnPB4Q6w7dHSb57E/VluBpVKmcQZN0dGdAkEIVty3v7kw9g
-y++VpCpWM/PstIFv4ApZMf501UY=
+ggEBABRChgo0Jo+iXSnTpODNongzZoU0sWqwx3/FQVo8nyAyr1qFuiqpSPb4bDbU
+DsVnUn3t0X/gGA8qJhutlmfTpEQCjUeyj2x9rWpD3lvttlGWV6btQ0qN4Dfc2gsw
+rCp9Jpful0HGWhiwfjWfsarqAdtLzIG0UC47IN7LGeCMRJIijOsXQhiZ915eNBEw
+g9+WSSGHkMFt/7vi2pFkvXSC0+RF8ovvRWf4Zw2aYXtJ1GElgi4ZS/s6ZU0gmv20
+i4SfC5m5UXIVZvOBYiMuZ/1B2m6R9xU41027zfOVwRFNtlVDiNfQRq6sDmz44At/
+dv8pkxXDgySe41vzlRXFsgIgz5A=
-----END CERTIFICATE-----
diff --git a/net-ssh.gemspec b/net-ssh.gemspec
index df564ed..d9fdc57 100644
--- a/net-ssh.gemspec
+++ b/net-ssh.gemspec
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
spec.description = %q{Net::SSH: a pure-Ruby implementation of the SSH2 client protocol. It allows you to write programs that invoke and interact with processes on remote servers, via SSH2.}
spec.homepage = "https://github.com/net-ssh/net-ssh"
spec.license = "MIT"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5")
spec.metadata = {
"changelog_uri" => "https://github.com/net-ssh/net-ssh/blob/master/CHANGES.txt"
}
@@ -40,5 +40,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "minitest", "~> 5.10"
spec.add_development_dependency "mocha", "~> 1.11.2"
spec.add_development_dependency "rake", "~> 12.0"
- spec.add_development_dependency "rubocop", "~> 0.74.0"
+ spec.add_development_dependency "rubocop", "~> 1.22.1"
end
diff --git a/support/ssh_tunnel_bug.rb b/support/ssh_tunnel_bug.rb
index d5fa09d..3f8f0ba 100755
--- a/support/ssh_tunnel_bug.rb
+++ b/support/ssh_tunnel_bug.rb
@@ -15,12 +15,12 @@
# visible_hostname netsshtest
# * Start squid squid -N -d 1 -D
# * Run this script
-# * Configure browser proxy to use localhost with LOCAL_PORT.
+# * Configure browser proxy to use localhost with LOCAL_PORT.
# * Load any page, wait for it to load fully. If the page loads
# correctly, move on. If not, something needs to be corrected.
# * Refresh the page several times. This should cause this
# script to failed with the error: "closed stream". You may
-# need to try a few times.
+# need to try a few times.
#
require 'highline/import'
@@ -37,7 +37,7 @@ pass = ask("Password: ") { |q| q.echo = "*" }
puts "Configure your browser proxy to localhost:#{LOCAL_PORT}"
begin
- session = Net::SSH.start(host, user, password: pass)
+ session = Net::SSH.start(host, user, password: pass)
session.forward.local(LOCAL_PORT, host, PROXY_PORT)
session.loop {true}
rescue StandardError => e
diff --git a/test/authentication/methods/common.rb b/test/authentication/methods/common.rb
index 77c6289..1162e8e 100644
--- a/test/authentication/methods/common.rb
+++ b/test/authentication/methods/common.rb
@@ -1,20 +1,19 @@
-module Authentication
+module Authentication
module Methods
-
module Common
include Net::SSH::Authentication::Constants
-
+
private
-
- def socket(options={})
+
+ def socket(options = {})
@socket ||= stub("socket", client_name: "me.ssh.test")
end
-
- def transport(options={})
+
+ def transport(options = {})
@transport ||= MockTransport.new(options.merge(socket: socket))
end
-
- def session(options={})
+
+ def session(options = {})
@session ||= begin
sess = stub("auth-session", logger: nil, transport: transport(options))
def sess.next_message
@@ -23,14 +22,12 @@ module Authentication
sess
end
end
-
+
def reset_session(options = {})
@transport = nil
@session = nil
session(options)
end
-
end
-
end
-end \ No newline at end of file
+end
diff --git a/test/authentication/methods/test_abstract.rb b/test/authentication/methods/test_abstract.rb
index a839699..c7944f0 100644
--- a/test/authentication/methods/test_abstract.rb
+++ b/test/authentication/methods/test_abstract.rb
@@ -4,7 +4,6 @@ require 'net/ssh/authentication/methods/abstract'
module Authentication
module Methods
-
class TestAbstract < NetSSHTest
include Common
@@ -43,7 +42,7 @@ module Authentication
private
- def subject(options={})
+ def subject(options = {})
@subject ||= Net::SSH::Authentication::Methods::Abstract.new(session(options), options)
end
end
diff --git a/test/authentication/methods/test_hostbased.rb b/test/authentication/methods/test_hostbased.rb
index 4fbd37a..99e42fe 100644
--- a/test/authentication/methods/test_hostbased.rb
+++ b/test/authentication/methods/test_hostbased.rb
@@ -4,7 +4,6 @@ require 'authentication/methods/common'
module Authentication
module Methods
-
class TestHostbased < NetSSHTest
include Common
@@ -57,21 +56,22 @@ module Authentication
def signature_parameters(key)
Proc.new do |given_key, data|
next false unless given_key.to_blob == key.to_blob
+
buffer = Net::SSH::Buffer.new(data)
buffer.read_string == "abcxyz123" && # session-id
- buffer.read_byte == USERAUTH_REQUEST && # type
- verify_userauth_request_packet(buffer, key)
+ buffer.read_byte == USERAUTH_REQUEST && # type
+ verify_userauth_request_packet(buffer, key)
end
end
def verify_userauth_request_packet(packet, key)
- packet.read_string == "jamis" && # user-name
- packet.read_string == "ssh-connection" && # next service
- packet.read_string == "hostbased" && # auth-method
- packet.read_string == key.ssh_type && # key type
- packet.read_buffer.read_key.to_blob == key.to_blob && # key
- packet.read_string == "me.ssh.test." && # client hostname
- packet.read_string == "jamis" # client username
+ packet.read_string == "jamis" && # user-name
+ packet.read_string == "ssh-connection" && # next service
+ packet.read_string == "hostbased" && # auth-method
+ packet.read_string == key.ssh_type && # key type
+ packet.read_buffer.read_key.to_blob == key.to_blob && # key
+ packet.read_string == "me.ssh.test." && # client hostname
+ packet.read_string == "jamis" # client username
end
@@keys = nil
@@ -79,7 +79,7 @@ module Authentication
@@keys ||= [OpenSSL::PKey::RSA.new(512), OpenSSL::PKey::DSA.new(512)]
end
- def key_manager(options={})
+ def key_manager(options = {})
@key_manager ||= begin
manager = stub("key_manager")
manager.stubs(:each_identity).multiple_yields(*(options[:keys] || keys))
@@ -87,20 +87,20 @@ module Authentication
end
end
- def subject(options={})
+ def subject(options = {})
options[:key_manager] = key_manager(options) unless options.key?(:key_manager)
@subject ||= Net::SSH::Authentication::Methods::Hostbased.new(session(options), options)
end
- def socket(options={})
+ def socket(options = {})
@socket ||= stub("socket", client_name: "me.ssh.test")
end
- def transport(options={})
+ def transport(options = {})
@transport ||= MockTransport.new(options.merge(socket: socket))
end
- def session(options={})
+ def session(options = {})
@session ||= begin
sess = stub("auth-session", logger: nil, transport: transport(options))
def sess.next_message
diff --git a/test/authentication/methods/test_keyboard_interactive.rb b/test/authentication/methods/test_keyboard_interactive.rb
index 9fad914..ebe9c16 100644
--- a/test/authentication/methods/test_keyboard_interactive.rb
+++ b/test/authentication/methods/test_keyboard_interactive.rb
@@ -2,71 +2,70 @@ require_relative '../../common'
require 'net/ssh/authentication/methods/keyboard_interactive'
require_relative 'common'
-module Authentication
+module Authentication
module Methods
-
class TestKeyboardInteractive < NetSSHTest
include Common
-
+
USERAUTH_INFO_REQUEST = 60
USERAUTH_INFO_RESPONSE = 61
-
+
def setup
reset_subject({}) if defined? @subject && !@subject.options.empty?
end
-
+
def test_authenticate_should_raise_if_keyboard_interactive_disallowed
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
assert_equal "jamis", packet.read_string
assert_equal "ssh-connection", packet.read_string
assert_equal "keyboard-interactive", packet.read_string
assert_equal "", packet.read_string # language tags
assert_equal "", packet.read_string # submethods
-
+
t.return(USERAUTH_FAILURE, :string, "password")
end
-
+
assert_raises Net::SSH::Authentication::DisallowedMethod do
subject.authenticate("ssh-connection", "jamis")
end
end
-
+
def test_authenticate_should_be_false_if_given_password_is_not_accepted
reset_subject(non_interactive: true)
-
- transport.expect do |t,packet|
+
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 1, :string, "Password:", :bool, false)
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
assert_equal 1, packet2.read_long
assert_equal "the-password", packet2.read_string
t2.return(USERAUTH_FAILURE, :string, "keyboard-interactive")
end
end
-
+
assert_equal false, subject.authenticate("ssh-connection", "jamis", "the-password")
end
-
+
def test_authenticate_should_be_true_if_given_password_is_accepted
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 1, :string, "Password:", :bool, false)
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
t2.return(USERAUTH_SUCCESS)
end
end
-
+
assert subject.authenticate("ssh-connection", "jamis", "the-password")
end
-
+
def test_authenticate_should_duplicate_password_as_needed_to_fill_request
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 2, :string, "Password:", :bool, false, :string, "Again:", :bool, false)
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
assert_equal 2, packet2.read_long
assert_equal "the-password", packet2.read_string
@@ -74,16 +73,16 @@ module Authentication
t2.return(USERAUTH_SUCCESS)
end
end
-
+
assert subject.authenticate("ssh-connection", "jamis", "the-password")
end
-
+
def test_authenticate_should_not_prompt_for_input_when_in_non_interactive_mode
reset_subject(non_interactive: true)
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 2, :string, "Name:", :bool, true, :string, "Password:", :bool, false)
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
assert_equal 2, packet2.read_long
assert_equal "", packet2.read_string
@@ -91,20 +90,20 @@ module Authentication
t2.return(USERAUTH_SUCCESS)
end
end
-
+
assert subject.authenticate("ssh-connection", "jamis", nil)
- end
-
+ end
+
def test_authenticate_should_prompt_for_input_when_password_is_not_given
prompt = MockPrompt.new
prompt.expects(:_ask).with("Name:", anything, true).returns("name")
prompt.expects(:_ask).with("Password:", anything, false).returns("password")
reset_subject(password_prompt: prompt)
-
- transport.expect do |t,packet|
+
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_INFO_REQUEST, :string, "", :string, "", :string, "", :long, 2, :string, "Name:", :bool, true, :string, "Password:", :bool, false)
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_INFO_RESPONSE, packet2.type
assert_equal 2, packet2.read_long
assert_equal "name", packet2.read_string
@@ -112,22 +111,21 @@ module Authentication
t2.return(USERAUTH_SUCCESS)
end
end
-
+
assert subject.authenticate("ssh-connection", "jamis", nil)
end
-
+
private
-
- def subject(options={})
+
+ def subject(options = {})
@subject ||= Net::SSH::Authentication::Methods::KeyboardInteractive.new(session(options), options)
end
-
+
def reset_subject(options)
@subject = nil
reset_session(options)
subject(options)
end
end
-
end
end
diff --git a/test/authentication/methods/test_none.rb b/test/authentication/methods/test_none.rb
index 8e31c08..f199172 100644
--- a/test/authentication/methods/test_none.rb
+++ b/test/authentication/methods/test_none.rb
@@ -2,42 +2,40 @@ require 'common'
require 'net/ssh/authentication/methods/none'
require 'authentication/methods/common'
-module Authentication
+module Authentication
module Methods
-
class TestNone < NetSSHTest
include Common
-
+
def test_authenticate_should_raise_if_none_disallowed
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
assert_equal "jamis", packet.read_string
assert_equal "ssh-connection", packet.read_string
assert_equal "none", packet.read_string
-
+
t.return(USERAUTH_FAILURE, :string, "publickey")
end
-
+
assert_raises Net::SSH::Authentication::DisallowedMethod do
subject.authenticate("ssh-connection", "jamis", "pass")
end
end
-
+
def test_authenticate_should_return_true
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_SUCCESS)
end
-
+
assert subject.authenticate("ssh-connection", "", "")
end
-
+
private
-
- def subject(options={})
+
+ def subject(options = {})
@subject ||= Net::SSH::Authentication::Methods::None.new(session(options), options)
end
end
-
end
end
diff --git a/test/authentication/methods/test_password.rb b/test/authentication/methods/test_password.rb
index d119fae..2205887 100644
--- a/test/authentication/methods/test_password.rb
+++ b/test/authentication/methods/test_password.rb
@@ -3,31 +3,30 @@ require 'net/ssh/authentication/methods/password'
require 'net/ssh/authentication/session'
require 'authentication/methods/common'
-module Authentication
+module Authentication
module Methods
-
class TestPassword < NetSSHTest
include Common
-
+
def test_authenticate_should_raise_if_password_disallowed
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
assert_equal "jamis", packet.read_string
assert_equal "ssh-connection", packet.read_string
assert_equal "password", packet.read_string
assert_equal false, packet.read_bool
assert_equal "the-password", packet.read_string
-
+
t.return(USERAUTH_FAILURE, :string, "publickey")
end
-
+
assert_raises Net::SSH::Authentication::DisallowedMethod do
subject.authenticate("ssh-connection", "jamis", "the-password")
end
end
-
+
def test_authenticate_ask_for_password_for_second_time_when_password_is_incorrect
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
assert_equal "jamis", packet.read_string
assert_equal "ssh-connection", packet.read_string
@@ -35,8 +34,8 @@ module Authentication
assert_equal false, packet.read_bool
assert_equal "the-password", packet.read_string
t.return(USERAUTH_FAILURE, :string, "publickey,password")
-
- t.expect do |t2, packet2|
+
+ t.expect do |_t2, packet2|
assert_equal USERAUTH_REQUEST, packet2.type
assert_equal "jamis", packet2.read_string
assert_equal "ssh-connection", packet2.read_string
@@ -46,14 +45,14 @@ module Authentication
t.return(USERAUTH_SUCCESS)
end
end
-
+
prompt = MockPrompt.new
prompt.expects(:_ask).with("jamis@'s password:", { type: 'password', user: 'jamis', host: nil }, false).returns("the-password-2")
subject(password_prompt: prompt).authenticate("ssh-connection", "jamis", "the-password")
end
-
+
def test_authenticate_ask_for_password_if_not_given
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
assert_equal "bill", packet.read_string
assert_equal "ssh-connection", packet.read_string
@@ -62,37 +61,36 @@ module Authentication
assert_equal "good-password", packet.read_string
t.return(USERAUTH_SUCCESS)
end
-
+
transport.instance_eval { @host = 'testhost' }
prompt = MockPrompt.new
prompt.expects(:_ask).with("bill@testhost's password:", { type: 'password', user: 'bill', host: 'testhost' }, false).returns("good-password")
subject(password_prompt: prompt).authenticate("ssh-connection", "bill", nil)
end
-
+
def test_authenticate_when_password_is_acceptible_should_return_true
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_SUCCESS)
end
-
+
assert subject.authenticate("ssh-connection", "jamis", "the-password")
end
-
+
def test_authenticate_should_return_false_if_password_change_request_is_received
- transport.expect do |t,packet|
+ transport.expect do |t, packet|
assert_equal USERAUTH_REQUEST, packet.type
t.return(USERAUTH_PASSWD_CHANGEREQ, :string, "Change your password:", :string, "")
end
-
+
assert !subject.authenticate("ssh-connection", "jamis", "the-password")
end
-
+
private
-
- def subject(options={})
+
+ def subject(options = {})
@subject ||= Net::SSH::Authentication::Methods::Password.new(session(options), options)
end
end
-
end
end
diff --git a/test/authentication/methods/test_publickey.rb b/test/authentication/methods/test_publickey.rb
index 8f2cc73..5e76ca0 100644
--- a/test/authentication/methods/test_publickey.rb
+++ b/test/authentication/methods/test_publickey.rb
@@ -4,7 +4,6 @@ require 'authentication/methods/common'
module Authentication
module Methods
-
class TestPublickey < NetSSHTest
include Common
@@ -40,7 +39,7 @@ module Authentication
assert verify_userauth_request_packet(packet, keys.first, false)
t.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first))
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_REQUEST, packet2.type
assert verify_userauth_request_packet(packet2, keys.first, true)
assert_equal "sig-one", packet2.read_string
@@ -62,7 +61,7 @@ module Authentication
assert verify_userauth_request_packet(packet, keys.first, false)
t.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first))
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_REQUEST, packet2.type
assert verify_userauth_request_packet(packet2, keys.first, true)
assert_equal "sig-one", packet2.read_string
@@ -73,7 +72,7 @@ module Authentication
assert verify_userauth_request_packet(packet3, keys.last, false)
t3.return(USERAUTH_PK_OK, :string, keys.last.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.last))
- t3.expect do |t4,packet4|
+ t3.expect do |t4, packet4|
assert_equal USERAUTH_REQUEST, packet4.type
assert verify_userauth_request_packet(packet4, keys.last, true)
assert_equal "sig-two", packet4.read_string
@@ -94,7 +93,7 @@ module Authentication
assert verify_userauth_request_packet(packet, keys.first, false)
t.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first))
- t.expect do |t2,packet2|
+ t.expect do |t2, packet2|
assert_equal USERAUTH_REQUEST, packet2.type
assert verify_userauth_request_packet(packet2, keys.first, true)
assert_equal "sig-one", packet2.read_string
@@ -105,25 +104,82 @@ module Authentication
assert subject.authenticate("ssh-connection", "jamis")
end
+ def test_authenticate_rsa_sha2
+ key_manager.expects(:sign).with(&signature_parameters_with_alg(keys.first, "rsa-sha2-256")).returns("sig-one")
+
+ transport.expect do |t, packet|
+ assert_equal USERAUTH_REQUEST, packet.type
+ assert verify_userauth_request_packet(packet, keys.first, false, "rsa-sha2-256")
+ t.return(USERAUTH_PK_OK, :string, "rsa-sha2-256", :string, Net::SSH::Buffer.from(:key, keys.first))
+
+ t.expect do |t2, packet2|
+ assert_equal USERAUTH_REQUEST, packet2.type
+ assert verify_userauth_request_packet(packet2, keys.first, true, "rsa-sha2-256")
+ assert_equal "sig-one", packet2.read_string
+ t2.return(USERAUTH_SUCCESS)
+ end
+ end
+
+ assert subject(pubkey_algorithms: %w[rsa-sha2-256]).authenticate("ssh-connection", "jamis")
+ end
+
+ def test_authenticate_rsa_sha2_fallback
+ key_manager.expects(:sign).with(&signature_parameters(keys.first)).returns("sig-one")
+
+ transport.expect do |t, packet|
+ assert_equal USERAUTH_REQUEST, packet.type
+ assert verify_userauth_request_packet(packet, keys.first, false, "rsa-sha2-256")
+ t.return(USERAUTH_FAILURE, :string, "publickey")
+
+ t.expect do |t2, packet2|
+ assert_equal USERAUTH_REQUEST, packet2.type
+ assert verify_userauth_request_packet(packet2, keys.first, false)
+ t2.return(USERAUTH_PK_OK, :string, keys.first.ssh_type, :string, Net::SSH::Buffer.from(:key, keys.first))
+
+ t2.expect do |t3, packet3|
+ assert_equal USERAUTH_REQUEST, packet3.type
+ assert verify_userauth_request_packet(packet3, keys.first, true)
+ assert_equal "sig-one", packet3.read_string
+ t3.return(USERAUTH_SUCCESS)
+ end
+ end
+ end
+
+ assert subject(pubkey_algorithms: %w[rsa-sha2-256 ssh-rsa]).authenticate("ssh-connection", "jamis")
+ end
+
private
def signature_parameters(key)
Proc.new do |given_key, data|
next false unless given_key.to_blob == key.to_blob
+
+ buffer = Net::SSH::Buffer.new(data)
+ buffer.read_string == "abcxyz123" && # session-id
+ buffer.read_byte == USERAUTH_REQUEST && # type
+ verify_userauth_request_packet(buffer, key, true)
+ end
+ end
+
+ def signature_parameters_with_alg(key, alg)
+ Proc.new do |given_key, data, given_alg|
+ next false unless given_key.to_blob == key.to_blob
+ next false unless given_alg == alg
+
buffer = Net::SSH::Buffer.new(data)
buffer.read_string == "abcxyz123" && # session-id
- buffer.read_byte == USERAUTH_REQUEST && # type
- verify_userauth_request_packet(buffer, key, true)
+ buffer.read_byte == USERAUTH_REQUEST && # type
+ verify_userauth_request_packet(buffer, key, true, alg)
end
end
- def verify_userauth_request_packet(packet, key, has_sig)
- packet.read_string == "jamis" && # user-name
- packet.read_string == "ssh-connection" && # next service
- packet.read_string == "publickey" && # auth-method
- packet.read_bool == has_sig && # whether a signature is appended
- packet.read_string == key.ssh_type && # ssh key type
- packet.read_buffer.read_key.to_blob == key.to_blob # key
+ def verify_userauth_request_packet(packet, key, has_sig, alg = nil)
+ packet.read_string == "jamis" && # user-name
+ packet.read_string == "ssh-connection" && # next service
+ packet.read_string == "publickey" && # auth-method
+ packet.read_bool == has_sig && # whether a signature is appended
+ packet.read_string == (alg || key.ssh_type) && # ssh key type
+ packet.read_buffer.read_key.to_blob == key.to_blob # key
end
@@keys = nil
@@ -131,7 +187,7 @@ module Authentication
@@keys ||= [OpenSSL::PKey::RSA.new(512), OpenSSL::PKey::DSA.new(512)]
end
- def key_manager(options={})
+ def key_manager(options = {})
@key_manager ||= begin
manager = stub("key_manager")
manager.stubs(:each_identity).multiple_yields(*(options[:keys] || keys))
@@ -139,8 +195,9 @@ module Authentication
end
end
- def subject(options={})
+ def subject(options = {})
options[:key_manager] = key_manager(options) unless options.key?(:key_manager)
+ options[:pubkey_algorithms] = %w[ssh-rsa] unless options.key?(:pubkey_algorithms)
@subject ||= Net::SSH::Authentication::Methods::Publickey.new(session(options), options)
end
end
diff --git a/test/authentication/test_agent.rb b/test/authentication/test_agent.rb
index 717550e..87247dc 100644
--- a/test/authentication/test_agent.rb
+++ b/test/authentication/test_agent.rb
@@ -2,7 +2,6 @@ require_relative '../common'
require 'net/ssh/authentication/agent'
module Authentication
-
class TestAgent < NetSSHTest
SSH2_AGENT_REQUEST_VERSION = 1
SSH2_AGENT_REQUEST_IDENTITIES = 11
@@ -12,6 +11,8 @@ module Authentication
SSH2_AGENT_ADD_IDENTITY = 17
SSH2_AGENT_REMOVE_IDENTITY = 18
SSH2_AGENT_REMOVE_ALL_IDENTITIES = 19
+ SSH2_AGENT_LOCK = 22
+ SSH2_AGENT_UNLOCK = 23
SSH2_AGENT_ADD_ID_CONSTRAINED = 25
SSH2_AGENT_FAILURE = 30
SSH2_AGENT_VERSION_RESPONSE = 103
@@ -35,7 +36,7 @@ module Authentication
Ics0b8bDqBzePaTbNxFUAAAAGmJhcnRsZUBCYXJ0bGVzLU1hY0Jvb2stUHJvAQID
-----END OPENSSH PRIVATE KEY-----
EOF
- CERT = "\x00\x00\x00\x1Cssh-rsa-cert-v01@openssh.com\x00\x00\x00 Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\xB3R\xBC\xF8\xEA\xA30\x90\x87\x85\xF6m\x80\xFB\x7F\x96%\xC0h\x85$\x05\x05J\x9BE\xD9\xDE\x81\xC0\xC9\xC2\xC0\x0F'\xD1TR\xCBb\xCD\xD0o\xA0\x15Q\x8B\xF26t\xC9!8\x85\xD2\f'\xC6\x14u\x1De\x90qyXl\a\x06\xA7\xD0\xB8 \xE1\xB3IP\xDE\xB5\xBE\x19\x0E\x97-M\xFDJT\x81\xE2\x8E>\xCD\x18\x9CJz\x1C\xB5}LsO\xF3\xAC\xAA\r\xAB\xF9\xD4\x83\x8DQ\x82\xE7F\xA4\x9F\x1C\x9A\xC5\xC3Y\x84k\x86\ef\xD7\x84\xE3\v\rlG\x15ya\xB0=\xDF\x11\x8D\x0FtZ/p\xBB\xB7g\xF5\xEBF8\xF5\x05}}\xDB\xFA\xA34dw\xE5\x80\xBC!=\x0E\x96\x18\bF\x10\a{\xFF\x9D2\xCA\xAAnu\x82\x82\xBA-F\x8C\x12\xBB\x04+nh\xE9N\xAF\fe\x16\x00Q\x9C\x1C\xCB\x94\x02\x8CQ\xFB,H[\x96\xF1Z4\nY]@\xE0\bs\x9Bh\x0E\xAA~\x105\x99\\\x8C\xA7q\x1A=\xA9\x9D\xBAbx\xF5`[\x8Aw\x80\b\xE0vy\x00\x00\x00\x00\x00\x00\x00c\x00\x00\x00\x01\x00\x00\x00\x06foobar\x00\x00\x00\b\x00\x00\x00\x04root\x00\x00\x00\x00Xk\\\x1C\x00\x00\x00\x00ZK>g\x00\x00\x00#\x00\x00\x00\rforce-command\x00\x00\x00\x0E\x00\x00\x00\n/bin/false\x00\x00\x00c\x00\x00\x00\x15permit-X11-forwarding\x00\x00\x00\x00\x00\x00\x00\x16permit-port-forwarding\x00\x00\x00\x00\x00\x00\x00\npermit-pty\x00\x00\x00\x00\x00\x00\x00\x0Epermit-user-rc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x17\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+\x00\x00\x01\x0F\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".force_encoding('BINARY')
+ CERT = "\x00\x00\x00\x1Cssh-rsa-cert-v01@openssh.com\x00\x00\x00 Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\xB3R\xBC\xF8\xEA\xA30\x90\x87\x85\xF6m\x80\xFB\x7F\x96%\xC0h\x85$\x05\x05J\x9BE\xD9\xDE\x81\xC0\xC9\xC2\xC0\x0F'\xD1TR\xCBb\xCD\xD0o\xA0\x15Q\x8B\xF26t\xC9!8\x85\xD2\f'\xC6\x14u\x1De\x90qyXl\a\x06\xA7\xD0\xB8 \xE1\xB3IP\xDE\xB5\xBE\x19\x0E\x97-M\xFDJT\x81\xE2\x8E>\xCD\x18\x9CJz\x1C\xB5}LsO\xF3\xAC\xAA\r\xAB\xF9\xD4\x83\x8DQ\x82\xE7F\xA4\x9F\x1C\x9A\xC5\xC3Y\x84k\x86\ef\xD7\x84\xE3\v\rlG\x15ya\xB0=\xDF\x11\x8D\x0FtZ/p\xBB\xB7g\xF5\xEBF8\xF5\x05}}\xDB\xFA\xA34dw\xE5\x80\xBC!=\x0E\x96\x18\bF\x10\a{\xFF\x9D2\xCA\xAAnu\x82\x82\xBA-F\x8C\x12\xBB\x04+nh\xE9N\xAF\fe\x16\x00Q\x9C\x1C\xCB\x94\x02\x8CQ\xFB,H[\x96\xF1Z4\nY]@\xE0\bs\x9Bh\x0E\xAA~\x105\x99\\\x8C\xA7q\x1A=\xA9\x9D\xBAbx\xF5`[\x8Aw\x80\b\xE0vy\x00\x00\x00\x00\x00\x00\x00c\x00\x00\x00\x01\x00\x00\x00\x06foobar\x00\x00\x00\b\x00\x00\x00\x04root\x00\x00\x00\x00Xk\\\x1C\x00\x00\x00\x00ZK>g\x00\x00\x00#\x00\x00\x00\rforce-command\x00\x00\x00\x0E\x00\x00\x00\n/bin/false\x00\x00\x00c\x00\x00\x00\x15permit-X11-forwarding\x00\x00\x00\x00\x00\x00\x00\x16permit-port-forwarding\x00\x00\x00\x00\x00\x00\x00\npermit-pty\x00\x00\x00\x00\x00\x00\x00\x0Epermit-user-rc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x17\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+\x00\x00\x01\x0F\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".dup.force_encoding('BINARY')
def setup
@original, ENV['SSH_AUTH_SOCK'] = ENV['SSH_AUTH_SOCK'], "/path/to/ssh.agent.sock"
@@ -75,7 +76,7 @@ module Authentication
end
def test_negotiate_should_raise_error_if_response_was_unexpected
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_VERSION, type
s.return(255)
end
@@ -83,7 +84,7 @@ module Authentication
end
def test_negotiate_should_be_successful_with_expected_response
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_VERSION, type
s.return(SSH_AGENT_RSA_IDENTITIES_ANSWER)
end
@@ -91,7 +92,7 @@ module Authentication
end
def test_identities_should_fail_if_SSH_AGENT_FAILURE_received
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
s.return(SSH_AGENT_FAILURE)
end
@@ -99,7 +100,7 @@ module Authentication
end
def test_identities_should_fail_if_SSH2_AGENT_FAILURE_received
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
s.return(SSH2_AGENT_FAILURE)
end
@@ -107,7 +108,7 @@ module Authentication
end
def test_identities_should_fail_if_SSH_COM_AGENT2_FAILURE_received
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
s.return(SSH_COM_AGENT2_FAILURE)
end
@@ -115,7 +116,7 @@ module Authentication
end
def test_identities_should_fail_if_response_is_not_SSH2_AGENT_IDENTITIES_ANSWER
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
s.return(255)
end
@@ -126,7 +127,7 @@ module Authentication
key1 = key
key2 = OpenSSL::PKey::DSA.new(512)
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
s.return(SSH2_AGENT_IDENTITIES_ANSWER, :long, 2, :string, Net::SSH::Buffer.from(:key, key1), :string, "My favorite key", :string, Net::SSH::Buffer.from(:key, key2), :string, "Okay, but not the best")
end
@@ -144,13 +145,13 @@ module Authentication
key2.to_blob[0..5] = 'badkey'
key3 = OpenSSL::PKey::DSA.new(512)
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
s.return(SSH2_AGENT_IDENTITIES_ANSWER, :long, 3, :string, Net::SSH::Buffer.from(:key, key1), :string, "My favorite key", :string, Net::SSH::Buffer.from(:key, key2), :string, "bad", :string, Net::SSH::Buffer.from(:key, key3), :string, "Okay, but not the best")
end
result = agent.identities
- assert_equal 2,result.size
+ assert_equal 2, result.size
assert_equal key1.to_blob, result.first.to_blob
assert_equal key3.to_blob, result.last.to_blob
assert_equal "My favorite key", result.first.comment
@@ -159,16 +160,16 @@ module Authentication
def test_identities_should_ignore_invalid_ones
key1 = key
- key2_bad = Net::SSH::Buffer.new("")
+ key2_bad = Net::SSH::Buffer.new(String.new)
key3 = OpenSSL::PKey::DSA.new(512)
- socket.expect do |s, type, buffer|
+ socket.expect do |s, type, _buffer|
assert_equal SSH2_AGENT_REQUEST_IDENTITIES, type
s.return(SSH2_AGENT_IDENTITIES_ANSWER, :long, 3, :string, Net::SSH::Buffer.from(:key, key1), :string, "My favorite key", :string, key2_bad, :string, "bad", :string, Net::SSH::Buffer.from(:key, key3), :string, "Okay, but not the best")
end
result = agent.identities
- assert_equal 2,result.size
+ assert_equal 2, result.size
assert_equal key1.to_blob, result.first.to_blob
assert_equal key3.to_blob, result.last.to_blob
assert_equal "My favorite key", result.first.comment
@@ -201,7 +202,7 @@ module Authentication
end
def test_sign_should_return_signed_data_from_agent
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_SIGN_REQUEST, type
assert_equal key.to_blob, Net::SSH::Buffer.new(buffer.read_string).read_key.to_blob
assert_equal "hello world", buffer.read_string
@@ -215,7 +216,7 @@ module Authentication
def test_add_rsa_identity_with_constraints
rsa = OpenSSL::PKey::RSA.new(512)
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_ID_CONSTRAINED, type
assert_equal buffer.read_string, "ssh-rsa"
assert_equal buffer.read_bignum.to_s, rsa.n.to_s
@@ -238,7 +239,7 @@ module Authentication
def test_add_rsa_cert_identity
cert = make_cert(OpenSSL::PKey::RSA.new(512))
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ssh-rsa-cert-v01@openssh.com"
assert_equal buffer.read_string, cert.to_blob
@@ -257,7 +258,7 @@ module Authentication
def test_add_dsa_identity
dsa = OpenSSL::PKey::DSA.new(512)
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ssh-dss"
assert_equal buffer.read_bignum.to_s, dsa.p.to_s
@@ -276,7 +277,7 @@ module Authentication
def test_add_dsa_cert_identity
cert = make_cert(OpenSSL::PKey::DSA.new(512))
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ssh-dss-cert-v01@openssh.com"
assert_equal buffer.read_string, cert.to_blob
@@ -292,7 +293,7 @@ module Authentication
def test_add_ecdsa_identity
ecdsa = OpenSSL::PKey::EC.new("prime256v1").generate_key
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ecdsa-sha2-nistp256"
assert_equal buffer.read_string, "nistp256"
@@ -309,7 +310,7 @@ module Authentication
def test_add_ecdsa_cert_identity
cert = make_cert(OpenSSL::PKey::EC.new("prime256v1").generate_key)
- socket.expect do |s,type,buffer|
+ 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"
assert_equal buffer.read_string, cert.to_blob
@@ -325,8 +326,9 @@ module Authentication
def test_add_ed25519_identity
return unless Net::SSH::Authentication::ED25519Loader::LOADED
+
ed25519 = Net::SSH::Authentication::ED25519::PrivKey.read(ED25519, nil)
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ssh-ed25519"
assert_equal buffer.read_string, ed25519.public_key.verify_key.to_bytes
@@ -342,8 +344,9 @@ module Authentication
def test_add_ed25519_cert_identity
return unless Net::SSH::Authentication::ED25519Loader::LOADED
+
cert = make_cert(Net::SSH::Authentication::ED25519::PrivKey.read(ED25519, nil))
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_ADD_IDENTITY, type
assert_equal buffer.read_string, "ssh-ed25519-cert-v01@openssh.com"
assert_equal buffer.read_string, cert.to_blob
@@ -359,7 +362,7 @@ module Authentication
end
def test_add_identity_should_raise_error_on_failure
- socket.expect do |s,type,buffer|
+ socket.expect do |s, _type, _buffer|
s.return(SSH_AGENT_FAILURE)
end
@@ -369,7 +372,7 @@ module Authentication
end
def test_remove_identity
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_REMOVE_IDENTITY, type
assert_equal buffer.read_string, key.to_blob
assert buffer.eof?
@@ -381,7 +384,7 @@ module Authentication
end
def test_remove_identity_should_raise_error_on_failure
- socket.expect do |s,type,buffer|
+ socket.expect do |s, _type, _buffer|
s.return(SSH_AGENT_FAILURE)
end
@@ -391,7 +394,7 @@ module Authentication
end
def test_remove_all_identities
- socket.expect do |s,type,buffer|
+ socket.expect do |s, type, buffer|
assert_equal SSH2_AGENT_REMOVE_ALL_IDENTITIES, type
assert buffer.eof?
@@ -402,7 +405,7 @@ module Authentication
end
def test_remove_all_identities_should_raise_error_on_failure
- socket.expect do |s,type,buffer|
+ socket.expect do |s, _type, _buffer|
s.return(SSH_AGENT_FAILURE)
end
@@ -436,6 +439,7 @@ module Authentication
def send(data, flags)
raise "got #{data.inspect} but no packet was expected" unless @expectation
+
buffer = Net::SSH::Buffer.new(data)
buffer.read_long # skip the length
type = buffer.read_byte
@@ -460,7 +464,7 @@ module Authentication
@factory ||= stub("socket factory", open: socket)
end
- def agent(auto=:connect)
+ def agent(auto = :connect)
@agent ||= begin
agent = Net::SSH::Authentication::Agent.new
agent.stubs(:unix_socket_class).returns(factory)
@@ -470,8 +474,7 @@ module Authentication
end
def agent_socket_factory
- @agent_socket_factory ||= -> {"/foo/bar.sock"}
+ @agent_socket_factory ||= -> { "/foo/bar.sock" }
end
end
-
end
diff --git a/test/authentication/test_certificate.rb b/test/authentication/test_certificate.rb
index 43802e0..de6691c 100644
--- a/test/authentication/test_certificate.rb
+++ b/test/authentication/test_certificate.rb
@@ -62,13 +62,13 @@ KEY = <<~EOF
EOF
# Generated via `ssh-keygen -s ca -I foobar -V +52w -O no-agent-forwarding -O force-command=/bin/false -z 99 key`.
-SIGNED_CERT = "\x00\x00\x00\x1Cssh-rsa-cert-v01@openssh.com\x00\x00\x00 Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\xB3R\xBC\xF8\xEA\xA30\x90\x87\x85\xF6m\x80\xFB\x7F\x96%\xC0h\x85$\x05\x05J\x9BE\xD9\xDE\x81\xC0\xC9\xC2\xC0\x0F'\xD1TR\xCBb\xCD\xD0o\xA0\x15Q\x8B\xF26t\xC9!8\x85\xD2\f'\xC6\x14u\x1De\x90qyXl\a\x06\xA7\xD0\xB8 \xE1\xB3IP\xDE\xB5\xBE\x19\x0E\x97-M\xFDJT\x81\xE2\x8E>\xCD\x18\x9CJz\x1C\xB5}LsO\xF3\xAC\xAA\r\xAB\xF9\xD4\x83\x8DQ\x82\xE7F\xA4\x9F\x1C\x9A\xC5\xC3Y\x84k\x86\ef\xD7\x84\xE3\v\rlG\x15ya\xB0=\xDF\x11\x8D\x0FtZ/p\xBB\xB7g\xF5\xEBF8\xF5\x05}}\xDB\xFA\xA34dw\xE5\x80\xBC!=\x0E\x96\x18\bF\x10\a{\xFF\x9D2\xCA\xAAnu\x82\x82\xBA-F\x8C\x12\xBB\x04+nh\xE9N\xAF\fe\x16\x00Q\x9C\x1C\xCB\x94\x02\x8CQ\xFB,H[\x96\xF1Z4\nY]@\xE0\bs\x9Bh\x0E\xAA~\x105\x99\\\x8C\xA7q\x1A=\xA9\x9D\xBAbx\xF5`[\x8Aw\x80\b\xE0vy\x00\x00\x00\x00\x00\x00\x00c\x00\x00\x00\x01\x00\x00\x00\x06foobar\x00\x00\x00\b\x00\x00\x00\x04root\x00\x00\x00\x00Xk\\\x1C\x00\x00\x00\x00ZK>g\x00\x00\x00#\x00\x00\x00\rforce-command\x00\x00\x00\x0E\x00\x00\x00\n/bin/false\x00\x00\x00c\x00\x00\x00\x15permit-X11-forwarding\x00\x00\x00\x00\x00\x00\x00\x16permit-port-forwarding\x00\x00\x00\x00\x00\x00\x00\npermit-pty\x00\x00\x00\x00\x00\x00\x00\x0Epermit-user-rc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x17\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+\x00\x00\x01\x0F\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".force_encoding('BINARY')
+SIGNED_CERT = "\x00\x00\x00\x1Cssh-rsa-cert-v01@openssh.com\x00\x00\x00 Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\xB3R\xBC\xF8\xEA\xA30\x90\x87\x85\xF6m\x80\xFB\x7F\x96%\xC0h\x85$\x05\x05J\x9BE\xD9\xDE\x81\xC0\xC9\xC2\xC0\x0F'\xD1TR\xCBb\xCD\xD0o\xA0\x15Q\x8B\xF26t\xC9!8\x85\xD2\f'\xC6\x14u\x1De\x90qyXl\a\x06\xA7\xD0\xB8 \xE1\xB3IP\xDE\xB5\xBE\x19\x0E\x97-M\xFDJT\x81\xE2\x8E>\xCD\x18\x9CJz\x1C\xB5}LsO\xF3\xAC\xAA\r\xAB\xF9\xD4\x83\x8DQ\x82\xE7F\xA4\x9F\x1C\x9A\xC5\xC3Y\x84k\x86\ef\xD7\x84\xE3\v\rlG\x15ya\xB0=\xDF\x11\x8D\x0FtZ/p\xBB\xB7g\xF5\xEBF8\xF5\x05}}\xDB\xFA\xA34dw\xE5\x80\xBC!=\x0E\x96\x18\bF\x10\a{\xFF\x9D2\xCA\xAAnu\x82\x82\xBA-F\x8C\x12\xBB\x04+nh\xE9N\xAF\fe\x16\x00Q\x9C\x1C\xCB\x94\x02\x8CQ\xFB,H[\x96\xF1Z4\nY]@\xE0\bs\x9Bh\x0E\xAA~\x105\x99\\\x8C\xA7q\x1A=\xA9\x9D\xBAbx\xF5`[\x8Aw\x80\b\xE0vy\x00\x00\x00\x00\x00\x00\x00c\x00\x00\x00\x01\x00\x00\x00\x06foobar\x00\x00\x00\b\x00\x00\x00\x04root\x00\x00\x00\x00Xk\\\x1C\x00\x00\x00\x00ZK>g\x00\x00\x00#\x00\x00\x00\rforce-command\x00\x00\x00\x0E\x00\x00\x00\n/bin/false\x00\x00\x00c\x00\x00\x00\x15permit-X11-forwarding\x00\x00\x00\x00\x00\x00\x00\x16permit-port-forwarding\x00\x00\x00\x00\x00\x00\x00\npermit-pty\x00\x00\x00\x00\x00\x00\x00\x0Epermit-user-rc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x17\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+\x00\x00\x01\x0F\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".dup.force_encoding('BINARY')
module Authentication
class TestCertificate < NetSSHTest
def test_certificate
cert = Net::SSH::Buffer.new(SIGNED_CERT).read_key
- assert_equal "Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF".force_encoding('BINARY'), cert.nonce
+ assert_equal "Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF".dup.force_encoding('BINARY'), cert.nonce
assert_equal 99, cert.serial
assert_equal :user, cert.type
assert_equal "foobar", cert.key_id
@@ -79,8 +79,8 @@ module Authentication
assert_equal({ "permit-X11-forwarding" => "", "permit-port-forwarding" => "",
"permit-pty" => "", "permit-user-rc" => "" }, cert.extensions)
assert_equal "", cert.reserved
- assert_equal "\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+".force_encoding('BINARY'), cert.signature_key.to_blob
- expected_signature = "\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".force_encoding('BINARY')
+ assert_equal "\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+".dup.force_encoding('BINARY'), cert.signature_key.to_blob
+ expected_signature = "\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".dup.force_encoding('BINARY')
assert_equal expected_signature, cert.signature
assert cert.signature_valid?
assert_equal SIGNED_CERT, cert.to_blob
diff --git a/test/authentication/test_ed25519.rb b/test/authentication/test_ed25519.rb
index 7430541..d0d0e9e 100644
--- a/test/authentication/test_ed25519.rb
+++ b/test/authentication/test_ed25519.rb
@@ -6,7 +6,6 @@ unless ENV['NET_SSH_NO_ED25519']
require 'base64'
module Authentication
-
class TestED25519 < NetSSHTest
def setup
raise "No ED25519 set NET_SSH_NO_ED25519 to ignore this test" unless Net::SSH::Authentication::ED25519Loader::LOADED
@@ -23,7 +22,7 @@ unless ENV['NET_SSH_NO_ED25519']
shared_secret = "Hello"
signed = priv_key.ssh_do_sign(shared_secret)
- self.assert_equal(true,pub_key.ssh_do_verify(signed,shared_secret))
+ self.assert_equal(true, pub_key.ssh_do_verify(signed, shared_secret))
self.assert_equal(priv_key.public_key.fingerprint, pub_key.fingerprint)
self.assert_equal(pub_key.fingerprint, key_fingerprint_md5_no_pwd)
self.assert_equal(pub_key.fingerprint('sha256'), key_fingerprint_sha256_no_pwd)
@@ -40,7 +39,7 @@ unless ENV['NET_SSH_NO_ED25519']
shared_secret = "Hello"
signed = priv_key.ssh_do_sign(shared_secret)
- self.assert_equal(true,pub_key.ssh_do_verify(signed,shared_secret))
+ self.assert_equal(true, pub_key.ssh_do_verify(signed, shared_secret))
self.assert_equal(priv_key.public_key.fingerprint, pub_key.fingerprint)
self.assert_equal(pub_key.fingerprint, key_fingerprint_md5_no_pwd)
self.assert_equal(pub_key.fingerprint('sha256'), key_fingerprint_sha256_no_pwd)
@@ -57,11 +56,11 @@ unless ENV['NET_SSH_NO_ED25519']
priv = private_key_pwd
pub_key = Net::SSH::Authentication::ED25519::PubKey.new(pub_data)
- priv_key = Net::SSH::Authentication::ED25519::PrivKey.read(priv,'pwd')
+ priv_key = Net::SSH::Authentication::ED25519::PrivKey.read(priv, 'pwd')
shared_secret = "Hello"
signed = priv_key.ssh_do_sign(shared_secret)
- self.assert_equal(true,pub_key.ssh_do_verify(signed,shared_secret))
+ self.assert_equal(true, pub_key.ssh_do_verify(signed, shared_secret))
self.assert_equal(priv_key.public_key.fingerprint, pub_key.fingerprint)
self.assert_equal(pub_key.fingerprint, key_fingerprint_md5_pwd)
self.assert_equal(pub_key.fingerprint('sha256'), key_fingerprint_sha256_pwd)
@@ -87,7 +86,7 @@ unless ENV['NET_SSH_NO_ED25519']
shared_secret = "Hello"
signed = priv_key.ssh_do_sign(shared_secret)
- self.assert_equal(true,pub_key.ssh_do_verify(signed,shared_secret))
+ self.assert_equal(true, pub_key.ssh_do_verify(signed, shared_secret))
self.assert_equal(priv_key.public_key.fingerprint, pub_key.fingerprint)
self.assert_equal(pub_key.fingerprint, key_fingerprint_md5_pwd)
self.assert_equal(pub_key.fingerprint('sha256'), key_fingerprint_sha256_pwd)
@@ -158,7 +157,6 @@ unless ENV['NET_SSH_NO_ED25519']
'SHA256:u6mXnY8P1b0FODGp8mckqOB33u8+jvkSCtJbD5Q9klg'
end
end
-
end
end
diff --git a/test/authentication/test_key_manager.rb b/test/authentication/test_key_manager.rb
index c40779f..05cb15d 100644
--- a/test/authentication/test_key_manager.rb
+++ b/test/authentication/test_key_manager.rb
@@ -2,7 +2,6 @@ require_relative '../common'
require 'net/ssh/authentication/key_manager'
module Authentication
-
class TestKeyManager < NetSSHTest
def test_key_files_and_known_identities_are_empty_by_default
assert manager.key_files.empty?
@@ -23,7 +22,7 @@ module Authentication
manager.add "/third"
manager.add "/second"
assert_equal 3, manager.key_files.length
- final_files = manager.key_files.map {|item| item.split('/').last}
+ final_files = manager.key_files.map { |item| item.split('/').last }
assert_equal %w[first second third], final_files
end
@@ -33,7 +32,7 @@ module Authentication
manager.add_keycert "/third"
manager.add_keycert "/second"
assert_equal 3, manager.keycert_files.length
- final_files = manager.keycert_files.map {|item| item.split('/').last}
+ final_files = manager.keycert_files.map { |item| item.split('/').last }
assert_equal %w[first second third], final_files
end
@@ -322,7 +321,7 @@ module Authentication
end
end
- def rsa(size=512)
+ def rsa(size = 512)
@rsa ||= OpenSSL::PKey::RSA.new(size)
end
@@ -381,5 +380,4 @@ module Authentication
@manager ||= Net::SSH::Authentication::KeyManager.new(nil, { password_prompt: prompt }.merge(options))
end
end
-
end
diff --git a/test/authentication/test_session.rb b/test/authentication/test_session.rb
index db37467..4f1d482 100644
--- a/test/authentication/test_session.rb
+++ b/test/authentication/test_session.rb
@@ -2,7 +2,6 @@ require_relative '../common'
require 'net/ssh/authentication/session'
module Authentication
-
class TestSession < NetSSHTest
include Net::SSH::Transport::Constants
include Net::SSH::Authentication::Constants
@@ -168,11 +167,13 @@ module Authentication
private
- def session(options={})
- @session ||= Net::SSH::Authentication::Session.new(transport(options), options)
+ def session(options = {})
+ session_opts = options.clone
+ session_opts[:pubkey_algorithms] = %w[ssh-rsa]
+ @session ||= Net::SSH::Authentication::Session.new(transport(options), session_opts)
end
- def transport(options={})
+ def transport(options = {})
@transport ||= MockTransport.new(options)
end
@@ -292,5 +293,4 @@ module Authentication
EOF
end
end
-
end
diff --git a/test/common.rb b/test/common.rb
index 8ae521c..e6a69bf 100644
--- a/test/common.rb
+++ b/test/common.rb
@@ -5,13 +5,13 @@ if ENV["CI"]
require 'simplecov'
SimpleCov.start
- require 'codecov'
- SimpleCov.formatter = SimpleCov::Formatter::Codecov
+ # require 'codecov'
+ # SimpleCov.formatter = SimpleCov::Formatter::Codecov
end
end
require 'minitest'
-require 'mocha/setup'
+require 'mocha/minitest'
require 'net/ssh/buffer'
require 'net/ssh/config'
require 'net/ssh/loggable'
@@ -94,7 +94,7 @@ class MockTransport < Net::SSH::Transport::Session
attr_accessor :mock_enqueue
- def initialize(options={})
+ def initialize(options = {})
@options = options
self.logger = options[:logger]
self.host_as_string = "net.ssh.test,127.0.0.1"
@@ -104,7 +104,7 @@ class MockTransport < Net::SSH::Transport::Session
@hints = {}
@socket = options[:socket]
@algorithms = OpenStruct.new(session_id: "abcxyz123")
- verifier { |data| true }
+ verifier { |_data| true }
end
def send_message(message)
@@ -161,7 +161,7 @@ class MockTransport < Net::SSH::Transport::Session
@server_options = options
end
- def hint(name, value=true)
+ def hint(name, value = true)
@hints[name] = value
end
end
diff --git a/test/connection/test_channel.rb b/test/connection/test_channel.rb
index abda254..c1d7c20 100644
--- a/test/connection/test_channel.rb
+++ b/test/connection/test_channel.rb
@@ -2,7 +2,6 @@ require 'common'
require 'net/ssh/connection/channel'
module Connection
-
class TestChannel < NetSSHTest
include Net::SSH::Connection::Constants
@@ -43,7 +42,7 @@ module Connection
def test_request_pty_without_options_should_use_defaults
channel.expects(:send_channel_request).with("pty-req", :string, "xterm",
- :long, 80, :long, 24, :long, 640, :long, 480, :string, "\0").yields
+ :long, 80, :long, 24, :long, 640, :long, 480, :string, "\0").yields
found_block = false
channel.request_pty { found_block = true }
assert found_block, "expected block to be passed to send_channel_request"
@@ -51,7 +50,7 @@ module Connection
def test_request_pty_with_options_should_honor_options
channel.expects(:send_channel_request).with("pty-req", :string, "vanilla",
- :long, 60, :long, 15, :long, 400, :long, 200, :string, "\5\0\0\0\1\0")
+ :long, 60, :long, 15, :long, 400, :long, 200, :string, "\5\0\0\0\1\0")
channel.request_pty term: "vanilla", chars_wide: 60, chars_high: 15,
pixels_wide: 400, pixels_high: 200, modes: { 5 => 1 }
end
@@ -73,7 +72,7 @@ module Connection
channel.do_open_confirmation(0, 100, 100)
assert !channel.closing?
- connection.expect { |t,packet| assert_equal CHANNEL_CLOSE, packet.type }
+ connection.expect { |_t, packet| assert_equal CHANNEL_CLOSE, packet.type }
connection.expects(:cleanup_channel).with(channel)
channel.close
@@ -112,7 +111,7 @@ module Connection
channel.do_open_confirmation(0, 100, 100)
channel.send_data("hello world")
- connection.expect do |t,packet|
+ connection.expect do |_t, packet|
assert_equal CHANNEL_DATA, packet.type
assert_equal 0, packet[:local_id]
assert_equal 11, packet[:data].length
@@ -125,12 +124,12 @@ module Connection
channel.do_open_confirmation(0, 100, 8)
channel.send_data("hello world")
- connection.expect do |t,packet|
+ connection.expect do |t, packet|
assert_equal CHANNEL_DATA, packet.type
assert_equal 0, packet[:local_id]
assert_equal "hello wo", packet[:data]
- t.expect do |t2,packet2|
+ t.expect do |_t2, packet2|
assert_equal CHANNEL_DATA, packet2.type
assert_equal 0, packet2[:local_id]
assert_equal "rld", packet2[:data]
@@ -144,7 +143,7 @@ module Connection
channel.do_open_confirmation(0, 8, 100)
channel.send_data("hello world")
- connection.expect do |t,packet|
+ connection.expect do |_t, packet|
assert_equal CHANNEL_DATA, packet.type
assert_equal 0, packet[:local_id]
assert_equal "hello wo", packet[:data]
@@ -210,7 +209,7 @@ module Connection
def test_do_request_for_unhandled_request_should_send_CHANNEL_FAILURE_if_wants_reply
channel.do_open_confirmation(0, 100, 100)
- connection.expect { |t,packet| assert_equal CHANNEL_FAILURE, packet.type }
+ connection.expect { |_t, packet| assert_equal CHANNEL_FAILURE, packet.type }
channel.do_request "keepalive@openssh.com", true, nil
end
@@ -234,7 +233,7 @@ module Connection
channel.do_open_confirmation(0, 100, 100)
flag = false
channel.on_request("exit-status") { flag = true; true }
- connection.expect { |t,p| assert_equal CHANNEL_SUCCESS, p.type }
+ connection.expect { |_t, p| assert_equal CHANNEL_SUCCESS, p.type }
assert_nothing_raised { channel.do_request "exit-status", true, nil }
assert flag, "callback should have been invoked"
end
@@ -243,14 +242,14 @@ module Connection
channel.do_open_confirmation(0, 100, 100)
flag = false
channel.on_request("exit-status") { flag = true; raise Net::SSH::ChannelRequestFailed }
- connection.expect { |t,p| assert_equal CHANNEL_FAILURE, p.type }
+ connection.expect { |_t, p| assert_equal CHANNEL_FAILURE, p.type }
assert_nothing_raised { channel.do_request "exit-status", true, nil }
assert flag, "callback should have been invoked"
end
def test_send_channel_request_without_callback_should_not_want_reply
channel.do_open_confirmation(0, 100, 100)
- connection.expect do |t,p|
+ connection.expect do |_t, p|
assert_equal CHANNEL_REQUEST, p.type
assert_equal 0, p[:local_id]
assert_equal "exec", p[:request]
@@ -275,7 +274,7 @@ module Connection
def test_send_channel_request_with_callback_should_want_reply
channel.do_open_confirmation(0, 100, 100)
- connection.expect do |t,p|
+ connection.expect do |_t, p|
assert_equal CHANNEL_REQUEST, p.type
assert_equal 0, p[:local_id]
assert_equal "exec", p[:request]
@@ -299,7 +298,7 @@ module Connection
flag = false
channel { flag = true }
assert !flag, "callback should not have been invoked yet"
- channel.do_open_confirmation(1,2,3)
+ channel.do_open_confirmation(1, 2, 3)
assert flag, "callback should have been invoked"
end
@@ -308,14 +307,14 @@ module Connection
forward = mock("forward")
forward.expects(:agent).with(channel)
connection.expects(:forward).returns(forward)
- channel.do_open_confirmation(1,2,3)
+ channel.do_open_confirmation(1, 2, 3)
end
def test_do_open_confirmation_with_non_session_channel_should_not_invoke_agent_forwarding_even_if_agent_forwarding_requested
connection forward_agent: true
channel type: "direct-tcpip"
connection.expects(:forward).never
- channel.do_open_confirmation(1,2,3)
+ channel.do_open_confirmation(1, 2, 3)
end
def test_do_window_adjust_should_adjust_remote_window_size_by_the_given_amount
@@ -348,7 +347,7 @@ module Connection
assert_equal 0x20000, channel.local_maximum_window_size
assert_equal 0x20000, channel.local_window_size
- connection.expect do |t,p|
+ connection.expect do |_t, p|
assert_equal CHANNEL_WINDOW_ADJUST, p.type
assert_equal 0, p[:local_id]
assert_equal 0x20000, p[:extra_bytes]
@@ -385,25 +384,25 @@ module Connection
end
def test_wait_should_block_while_channel_is_active?
- channel.expects(:active?).times(3).returns(true,true,false)
+ channel.expects(:active?).times(3).returns(true, true, false)
channel.wait
end
def test_wait_until_open_confirmed_should_block_while_remote_id_nil
- channel.expects(:remote_id).times(3).returns(nil,nil,3)
+ channel.expects(:remote_id).times(3).returns(nil, nil, 3)
channel.send(:wait_until_open_confirmed)
end
def test_eof_bang_should_send_eof_to_server
channel.do_open_confirmation(0, 1000, 1000)
- connection.expect { |t,p| assert_equal CHANNEL_EOF, p.type }
+ connection.expect { |_t, p| assert_equal CHANNEL_EOF, p.type }
channel.eof!
channel.process
end
def test_eof_bang_should_not_send_eof_if_eof_was_already_declared
channel.do_open_confirmation(0, 1000, 1000)
- connection.expect { |t,p| assert_equal CHANNEL_EOF, p.type }
+ connection.expect { |_t, p| assert_equal CHANNEL_EOF, p.type }
channel.eof!
assert_nothing_raised { channel.eof! }
channel.process
@@ -411,7 +410,7 @@ module Connection
def test_eof_q_should_return_true_if_eof_declared
channel.do_open_confirmation(0, 1000, 1000)
- connection.expect { |t,p| assert_equal CHANNEL_EOF, p.type }
+ connection.expect { |_t, p| assert_equal CHANNEL_EOF, p.type }
assert !channel.eof?
channel.eof!
@@ -421,7 +420,7 @@ module Connection
def test_send_data_should_raise_exception_if_eof_declared
channel.do_open_confirmation(0, 1000, 1000)
- connection.expect { |t,p| assert_equal CHANNEL_EOF, p.type }
+ connection.expect { |_t, p| assert_equal CHANNEL_EOF, p.type }
channel.eof!
channel.process
assert_raises(EOFError) { channel.send_data("die! die! die!") }
@@ -429,9 +428,9 @@ module Connection
def test_data_should_precede_eof
channel.do_open_confirmation(0, 1000, 1000)
- connection.expect do |_t,p|
+ connection.expect do |_t, p|
assert_equal CHANNEL_DATA, p.type
- connection.expect { |_t,p2| assert_equal CHANNEL_EOF, p2.type }
+ connection.expect { |_t, p2| assert_equal CHANNEL_EOF, p2.type }
end
channel.send_data "foo"
channel.eof!
@@ -445,7 +444,7 @@ module Connection
attr_reader :options
attr_reader :channels
- def initialize(options={})
+ def initialize(options = {})
@expectation = nil
@options = options
@channels = {}
@@ -457,6 +456,7 @@ module Connection
def send_message(msg)
raise "#{msg.to_s.inspect} received but no message was expected" unless @expectation
+
packet = Net::SSH::Packet.new(msg.to_s)
callback, @expectation = @expectation, nil
callback.call(self, packet)
@@ -472,16 +472,15 @@ module Connection
end
end
- def connection(options={})
+ def connection(options = {})
@connection ||= MockConnection.new(options)
end
- def channel(options={}, &block)
+ def channel(options = {}, &block)
@channel ||= Net::SSH::Connection::Channel.new(connection(options),
- options[:type] || "session",
- options[:local_id] || 0,
- &block)
+ options[:type] || "session",
+ options[:local_id] || 0,
+ &block)
end
end
-
end
diff --git a/test/connection/test_session.rb b/test/connection/test_session.rb
index 91e3ea9..5de5fd2 100644
--- a/test/connection/test_session.rb
+++ b/test/connection/test_session.rb
@@ -2,7 +2,6 @@ require_relative '../common'
require 'net/ssh/connection/session'
module Connection
-
class TestSession < NetSSHTest
include Net::SSH::Connection::Constants
@@ -62,14 +61,14 @@ module Connection
flag = false
channel = session.open_channel { flag = true }
assert !flag, "callback should not be invoked immediately"
- channel.do_open_confirmation(1,2,3)
+ channel.do_open_confirmation(1, 2, 3)
assert flag, "callback should have been invoked"
assert_equal "session", channel.type
assert_equal 0, channel.local_id
assert_equal channel, session.channels[channel.local_id]
packet = P(:byte, CHANNEL_OPEN, :string, "session", :long, channel.local_id,
- :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
+ :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
assert_equal packet.to_s, socket.write_buffer
end
@@ -77,15 +76,15 @@ module Connection
channel = session.open_channel("direct-tcpip")
assert_equal "direct-tcpip", channel.type
packet = P(:byte, CHANNEL_OPEN, :string, "direct-tcpip", :long, channel.local_id,
- :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
+ :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
assert_equal packet.to_s, socket.write_buffer
end
def test_open_channel_with_extras_should_append_extras_to_packet
channel = session.open_channel("direct-tcpip", :string, "other.host", :long, 1234)
packet = P(:byte, CHANNEL_OPEN, :string, "direct-tcpip", :long, channel.local_id,
- :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size,
- :string, "other.host", :long, 1234)
+ :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size,
+ :string, "other.host", :long, 1234)
assert_equal packet.to_s, socket.write_buffer
end
@@ -225,7 +224,7 @@ module Connection
def test_channel_open_packet_with_corresponding_handler_should_result_in_channel_open_failure_when_handler_returns_an_error
transport.return(CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20000, :long, 0x10000)
- session.on_open_channel "auth-agent" do |s, ch, p|
+ session.on_open_channel "auth-agent" do |_s, _ch, _p|
raise Net::SSH::ChannelOpenFailed.new(1234, "we iz in ur channelz!")
end
process_times(2)
@@ -336,19 +335,19 @@ module Connection
end
def test_writers_without_pending_writes_should_not_be_considered_for_select
- IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
+ IO.expects(:select).with([socket], [], nil, nil).returns([[], [], []])
session.process
end
def test_writers_with_pending_writes_should_be_considered_for_select
socket.enqueue("laksdjflasdkf")
- IO.expects(:select).with([socket],[socket],nil,nil).returns([[],[],[]])
+ IO.expects(:select).with([socket], [socket], nil, nil).returns([[], [], []])
session.process
end
def test_ready_readers_should_be_filled
socket.expects(:recv).returns("this is some data")
- IO.expects(:select).with([socket],[],nil,nil).returns([[socket],[],[]])
+ IO.expects(:select).with([socket], [], nil, nil).returns([[socket], [], []])
session.process
assert_equal [socket], session.listeners.keys
end
@@ -356,7 +355,7 @@ module Connection
def test_ready_readers_that_cant_be_filled_should_be_removed
socket.expects(:recv).returns("")
socket.expects(:close)
- IO.expects(:select).with([socket],[],nil,nil).returns([[socket],[],[]])
+ IO.expects(:select).with([socket], [], nil, nil).returns([[socket], [], []])
session.process
assert session.listeners.empty?
end
@@ -366,7 +365,7 @@ module Connection
flag = false
session.stop_listening_to(socket) # so that we only have to test the presence of a single IO object
session.listen_to(io) { flag = true }
- IO.expects(:select).with([io],[],nil,nil).returns([[io],[],[]])
+ IO.expects(:select).with([io], [], nil, nil).returns([[io], [], []])
session.process
assert flag, "callback should have been invoked"
end
@@ -374,13 +373,13 @@ module Connection
def test_ready_writers_should_call_send_pending
socket.enqueue("laksdjflasdkf")
socket.expects(:send).with("laksdjflasdkf", 0).returns(13)
- IO.expects(:select).with([socket],[socket],nil,nil).returns([[],[socket],[]])
+ IO.expects(:select).with([socket], [socket], nil, nil).returns([[], [socket], []])
session.process
end
def test_process_should_call_rekey_as_needed
transport.expects(:rekey_as_needed)
- IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
+ IO.expects(:select).with([socket], [], nil, nil).returns([[], [], []])
session.process
end
@@ -388,7 +387,7 @@ module Connection
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
options = { keepalive: true }
expected_packet = P(:byte, Net::SSH::Packet::GLOBAL_REQUEST, :string, "keepalive@openssh.com", :bool, true)
- IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
+ IO.stubs(:select).with([socket], [], nil, timeout).returns(nil)
transport.expects(:enqueue_message).with { |msg| msg.content == expected_packet.content }
session(options).process
end
@@ -397,15 +396,15 @@ module Connection
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
options = { keepalive: true, keepalive_interval: 300, keepalive_maxcount: 3 }
expected_packet = P(:byte, Net::SSH::Packet::GLOBAL_REQUEST, :string, "keepalive@openssh.com", :bool, true)
- [1,2,3].each do |i|
+ [1, 2, 3].each do |i|
Time.stubs(:now).returns(Time.at(i * 300))
- IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
+ IO.stubs(:select).with([socket], [], nil, timeout).returns(nil)
transport.expects(:enqueue_message).with { |msg| msg.content == expected_packet.content }
session(options).process
end
Time.stubs(:now).returns(Time.at(4 * 300))
- IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
+ IO.stubs(:select).with([socket], [], nil, timeout).returns(nil)
transport.expects(:enqueue_message).with { |msg| msg.content == expected_packet.content }
assert_raises(Net::SSH::Timeout) { session(options).process }
end
@@ -413,7 +412,7 @@ module Connection
def test_process_should_not_call_enqueue_message_unless_io_select_timed_out
timeout = Net::SSH::Connection::Session::DEFAULT_IO_SELECT_TIMEOUT
options = { keepalive: true }
- IO.stubs(:select).with([socket],[],nil,timeout).returns([[socket],[],[]])
+ IO.stubs(:select).with([socket], [], nil, timeout).returns([[socket], [], []])
socket.stubs(:recv).returns("x")
transport.expects(:enqueue_message).never
session(options).process
@@ -423,20 +422,20 @@ module Connection
timeout = 10
options = { keepalive: true, keepalive_interval: timeout }
Time.stubs(:now).returns(Time.at(0), Time.at(9), Time.at(timeout))
- IO.stubs(:select).with([socket],[],nil,timeout).returns(nil)
+ IO.stubs(:select).with([socket], [], nil, timeout).returns(nil)
transport.expects(:enqueue_message).times(2)
3.times { session(options).process }
end
def test_process_should_call_io_select_with_nil_as_last_arg_if_keepalive_disabled
- IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
+ IO.expects(:select).with([socket], [], nil, nil).returns([[], [], []])
session.process
end
def test_process_should_call_io_select_with_interval_as_last_arg_if_keepalive_interval_passed
timeout = 10
options = { keepalive: true, keepalive_interval: timeout }
- IO.expects(:select).with([socket],[],nil,timeout).returns([[],[],[]])
+ IO.expects(:select).with([socket], [], nil, timeout).returns([[], [], []])
session(options).process
end
@@ -444,13 +443,13 @@ module Connection
timeout = 10
wait = 5
options = { keepalive: true, keepalive_interval: timeout }
- IO.expects(:select).with([socket],[],nil,wait).returns([[],[],[]])
+ IO.expects(:select).with([socket], [], nil, wait).returns([[], [], []])
session(options).process(wait)
end
def test_loop_should_call_process_until_process_returns_false
session.expects(:process).with(0)
- session.expects(:process).with(nil).times(4).returns(true,true,true,false).yields
+ session.expects(:process).with(nil).times(4).returns(true, true, true, false).yields
n = 0
session.loop { n += 1 }
assert_equal 4, n
@@ -460,7 +459,7 @@ module Connection
prep_exec("ls", :stdout, "data packet", :stderr, "extended data packet")
call = :first
- session.exec "ls" do |channel, type, data|
+ session.exec "ls" do |_channel, type, data|
if call == :first
assert_equal :stdout, type
assert_equal "data packet", data
@@ -490,7 +489,7 @@ module Connection
def test_exec_bang_should_block_until_command_finishes
prep_exec("ls", :stdout, "some data")
called = false
- session.exec! "ls" do |channel, type, data|
+ session.exec! "ls" do |_channel, type, data|
called = true
assert_equal :stdout, type
assert_equal "some data", data
@@ -521,7 +520,7 @@ module Connection
private
def prep_exec(command, *data)
- IO.expects(:select).with([socket],[],nil,0).returns([[],[],[]])
+ IO.expects(:select).with([socket], [], nil, 0).returns([[], [], []])
transport.mock_enqueue = true
transport.expect do |t, p|
assert_equal CHANNEL_OPEN, p.type
@@ -536,6 +535,7 @@ module Connection
data.each_slice(2) do |type, datum|
next if datum.empty?
+
if type == :stdout
t2.return(CHANNEL_DATA, :long, p[:remote_id], :string, datum)
else
@@ -544,7 +544,7 @@ module Connection
end
t2.return(CHANNEL_CLOSE, :long, p[:remote_id])
- t2.expect { |t3,p3| assert_equal CHANNEL_CLOSE, p3.type }
+ t2.expect { |_t3, p3| assert_equal CHANNEL_CLOSE, p3.type }
end
end
end
@@ -570,11 +570,11 @@ module Connection
session.channels[local_id] = stub("channel", process: true, local_closed?: false)
end
- def transport(options={})
+ def transport(options = {})
@transport ||= MockTransport.new(options.merge(socket: socket))
end
- def session(options={})
+ def session(options = {})
@session ||= Net::SSH::Connection::Session.new(transport, options)
end
@@ -583,5 +583,4 @@ module Connection
session.process { (i += 1) < n }
end
end
-
end
diff --git a/test/integration/Vagrantfile b/test/integration/Vagrantfile
index 2c42d9a..2327e5d 100644
--- a/test/integration/Vagrantfile
+++ b/test/integration/Vagrantfile
@@ -1,10 +1,11 @@
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
- config.vm.box = "ubuntu/trusty64"
+ config.vm.box = "ubuntu/bionic64"
config.vm.provision "ansible" do |ansible|
ansible.playbook = "./playbook.yml"
- ansible.sudo = true
+ ansible.become = true
+ ansible.become_user = 'root'
ansible.verbose = 'vvvv'
ansible.compatibility_mode = "2.0"
end
diff --git a/test/integration/common.rb b/test/integration/common.rb
index 6295ada..9f56fe9 100644
--- a/test/integration/common.rb
+++ b/test/integration/common.rb
@@ -20,14 +20,14 @@ module IntegrationTestHelpers
end
end
- def set_authorized_key(user,pubkey)
+ def set_authorized_key(user, pubkey)
authorized_key = "/home/#{user}/.ssh/authorized_keys"
sh "sudo cp #{pubkey} #{authorized_key}"
sh "sudo chown #{user} #{authorized_key}"
sh "sudo chmod 0744 #{authorized_key}"
end
- def sign_user_key(user,pubkey)
+ def sign_user_key(user, pubkey)
cert = "/etc/ssh/users_ca"
sh "sudo ssh-keygen -s #{cert} -I user_#{user} -n #{user} -V +52w #{pubkey}"
end
@@ -48,7 +48,7 @@ module IntegrationTestHelpers
end
end
- def ssh_add(key,password)
+ def ssh_add(key, password)
command = "ssh-add #{key}"
status = nil
PTY.spawn(command) do |reader, writer, pid|
@@ -64,11 +64,13 @@ module IntegrationTestHelpers
pid, status = Process.wait2 pid
end
raise "Command: #{command} failed:#{status.exitstatus}" unless status
+
status.exitstatus
end
def with_sshd_config(sshd_config, &block)
raise "Failed to copy config" unless system("sudo cp -f /etc/ssh/sshd_config /etc/ssh/sshd_config.original")
+
begin
Tempfile.open('sshd_config') do |f|
f.write(sshd_config)
@@ -77,6 +79,7 @@ module IntegrationTestHelpers
end
system("sudo chmod 0644 /etc/ssh/sshd_config")
raise "Failed to restart sshd" unless system("sudo service ssh restart")
+
yield
ensure
system("sudo cp -f /etc/ssh/sshd_config.original /etc/ssh/sshd_config")
@@ -84,33 +87,74 @@ module IntegrationTestHelpers
end
end
- def with_lines_as_tempfile(lines = [], &block)
+ def with_lines_as_tempfile(lines = [], add_pid: true, debug: false, &block)
Tempfile.open('sshd_config') do |f|
- f.write(lines)
+ f.write(lines.join("\n"))
+ pidpath = nil
+ if add_pid
+ pidpath = f.path + '.pid'
+ f.write("\nPidFile #{pidpath}\n")
+ end
+ f.write("\nLogLevel DEBUG3\n") if debug
f.close
- yield(f.path)
+ puts "CONFIG: #{f.path} PID: #{pidpath}" if debug
+ yield(f.path, pidpath)
end
end
+ def port_open?(path)
+ Socket.tcp("localhost", 10567, connect_timeout: 1) { true } rescue false # rubocop:disable Style/RescueModifier
+ end
+
# @yield [pid, port]
- def start_sshd_7_or_later(port = '2200', config: nil)
+ def start_sshd_7_or_later(port = '2200', config: nil, debug: false)
pid = nil
+ sshpidfile = nil
if config
- with_lines_as_tempfile(config) do |path|
- pid = spawn('sudo', '/opt/net-ssh-openssh/sbin/sshd', '-D', '-f', path, '-p', port)
+ with_lines_as_tempfile(config, debug: debug) do |path, pidpath|
+ puts "DEBUG - SSH LOG: #{path}-log.txt config: #{path}" if debug
+ raise "A leftover sshd is already running" if port_open?(port)
+
+ extra_params = []
+ extra_params = ['-E', "#{path}-log.txt"] if debug
+ pid = spawn('sudo', '/opt/net-ssh-openssh/sbin/sshd', '-D', '-f', path, '-p', port, *extra_params)
+ sshpidfile = pidpath
yield pid, port
end
else
- pid = spawn('sudo', '/opt/net-ssh-openssh/sbin/sshd', '-D', '-p', port)
- yield pid, port
+ with_lines_as_tempfile(['']) do |path, pidpath|
+ pid = spawn('sudo', '/opt/net-ssh-openssh/sbin/sshd', '-D', '-f', path, '-p', port)
+ sshpidfile = pidpath
+ yield pid, port
+ end
end
ensure
- # Our pid is sudo, -9 (KILL) on sudo will not clean up its children
+ # Our pid is sudo and not sshd, -9 (KILL) on sudo will not clean up its children
# properly, so we just have to hope that -15 (TERM) will manage to bring
# down sshd.
- if pid
+ if sshpidfile
+ sshpid = File.read(sshpidfile).strip
+ system('sudo', 'kill', '-15', sshpid.to_s)
+ begin
+ Timeout.timeout(20) do
+ Process.wait(pid)
+ end
+ rescue Timeout::Error
+ warn "Failed to kill openssh process: #{sshpid}"
+ system('sudo', 'kill', '-9', sshpid.to_s)
+ raise
+ end
+ elsif pid
system('sudo', 'kill', '-15', pid.to_s)
- Process.wait(pid)
+ begin
+ Timeout.timeout(20) do
+ Process.wait(pid)
+ end
+ rescue Timeout::Error
+ warn "Failed to kill openssh process: #{pid}"
+ system('sudo', 'kill', '-9', pid.to_s)
+ raise
+ end
end
end
diff --git a/test/integration/mitm_server.rb b/test/integration/mitm_server.rb
index e063687..750748c 100644
--- a/test/integration/mitm_server.rb
+++ b/test/integration/mitm_server.rb
@@ -49,10 +49,10 @@ class MitmServer < TCPServer
server = start_server(server) do |local|
remote = TCPSocket.new(remote_host, remote_port)
loop do
- r,_w,_e = IO.select([local, remote],nil,nil)
+ r, _w, _e = IO.select([local, remote], nil, nil)
if r.include? local
begin
- data = local.recv local_read_size
+ data = local.recv local_read_size
rescue StandardError => e
data = nil
dlog "Local closed: #{e}"
diff --git a/test/integration/playbook.yml b/test/integration/playbook.yml
index 47eba34..828dda2 100644
--- a/test/integration/playbook.yml
+++ b/test/integration/playbook.yml
@@ -8,11 +8,10 @@
homedir: /home/vagrant
ruby_version: '2.0.0-p598'
ruby_versions:
- - '2.3.8'
- - '2.4.10'
- '2.5.8'
- '2.6.6'
- '2.7.1'
+ - '3.0.1'
# - 'ruby-head'
# - 'rbx-3.19'
# - 'jruby-9.0.5.0'
@@ -35,6 +34,10 @@
rvm1_gpg_key_server: pool.sks-keyservers.net,
when: "'{{current_ruby_version.stdout|default()}}' != '{{ruby_version}}' and not no_rvm" }
tasks:
+ - name: Install packages
+ apt:
+ pkg:
+ - libssl-dev
- group: name="{{mygroup}}" state=present
- user: name=net_ssh_1 password="{{foopwd}}" group="{{mygroup}}" state=present
- user: name=net_ssh_2 password="{{foo2pwd}}" group="{{mygroup}}" state=present
@@ -80,26 +83,46 @@
lineinfile: dest='/etc/ssh/sshd_config' line='TrustedUserCAKeys /etc/ssh/users_ca.pub'
notify: restart sshd
- name: sshd allow forward
- lineinfile: dest='/etc/ssh/sshd_config' line='AllowTcpForwarding all' regexp=LogLevel
+ lineinfile: dest='/etc/ssh/sshd_config' line='AllowTcpForwarding all' regexp=AllowTcpForwarding
notify: restart sshd
- name: sshd allow forward
- lineinfile: dest='/etc/ssh/sshd_config' line='GatewayPorts yes' regexp=LogLevel
+ lineinfile: dest='/etc/ssh/sshd_config' line='GatewayPorts yes' regexp=GatewayPorts
+ notify: restart sshd
+ - name: disable x11 forward
+ lineinfile: dest='/etc/ssh/sshd_config' line='X11Forwarding no' regexp=X11Forwarding
+ notify: restart sshd
+ - name: sshd allow forward
+ lineinfile: dest='/etc/ssh/sshd_config' line='#PasswordAuthentication no' regexp='#?PasswordAuthentication.+no'
+ notify: restart sshd
+ - name: sshd allow forward
+ lineinfile: dest='/etc/ssh/sshd_config' line='PasswordAuthentication yes' regexp=PasswordAuthentication
notify: restart sshd
- name: put NET_SSH_RUN_INTEGRATION_TESTS=YES environment
lineinfile: dest='/etc/environment' line='NET_SSH_RUN_INTEGRATION_TESTS=YES'
- name: change dir in bashrc
lineinfile: dest="{{homedir}}/.bashrc" owner="{{myuser}}" mode=0644
regexp='^cd ' line='cd /net-ssh'
- - name: add host aliases
+ - name: add host aliases1
lineinfile: dest='/etc/hosts' owner='root' group='root' mode=0644
regexp='^127\.0\.0\.1\s+gateway.netssh' line='127.0.0.1 gateway.netssh'
- - apt:
+ - name: add host aliases2
+ lineinfile: dest='/etc/hosts' owner='root' group='root' mode=0644
+ regexp='^127\.0\.0\.1\s+one.hosts.netssh' line='127.0.0.1 one.hosts.netssh'
+ - name: Update APT Cache
+ apt:
+ update_cache: yes
+ force_apt_get: yes
+ - name: Wait for locfile removal
+ become: yes
+ shell: while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 5; done;
+ - name: Install packages
+ apt:
pkg:
- pv
- libgmp3-dev
- git
+ - libssl-dev
state: present
- update_cache: yes
- copy: content='echo "cd /net-ssh ; rake integration-test"' dest=/etc/update-motd.d/99-net-ssh-tests mode=0755
- name: add user to rvm group so they can change gem wrappers
user:
diff --git a/test/integration/test_agent.rb b/test/integration/test_agent.rb
index 4045c9a..294a1b8 100644
--- a/test/integration/test_agent.rb
+++ b/test/integration/test_agent.rb
@@ -1,7 +1,7 @@
require_relative 'common'
require 'net/ssh'
-CERT = "\x00\x00\x00\x1Cssh-rsa-cert-v01@openssh.com\x00\x00\x00 Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\xB3R\xBC\xF8\xEA\xA30\x90\x87\x85\xF6m\x80\xFB\x7F\x96%\xC0h\x85$\x05\x05J\x9BE\xD9\xDE\x81\xC0\xC9\xC2\xC0\x0F'\xD1TR\xCBb\xCD\xD0o\xA0\x15Q\x8B\xF26t\xC9!8\x85\xD2\f'\xC6\x14u\x1De\x90qyXl\a\x06\xA7\xD0\xB8 \xE1\xB3IP\xDE\xB5\xBE\x19\x0E\x97-M\xFDJT\x81\xE2\x8E>\xCD\x18\x9CJz\x1C\xB5}LsO\xF3\xAC\xAA\r\xAB\xF9\xD4\x83\x8DQ\x82\xE7F\xA4\x9F\x1C\x9A\xC5\xC3Y\x84k\x86\ef\xD7\x84\xE3\v\rlG\x15ya\xB0=\xDF\x11\x8D\x0FtZ/p\xBB\xB7g\xF5\xEBF8\xF5\x05}}\xDB\xFA\xA34dw\xE5\x80\xBC!=\x0E\x96\x18\bF\x10\a{\xFF\x9D2\xCA\xAAnu\x82\x82\xBA-F\x8C\x12\xBB\x04+nh\xE9N\xAF\fe\x16\x00Q\x9C\x1C\xCB\x94\x02\x8CQ\xFB,H[\x96\xF1Z4\nY]@\xE0\bs\x9Bh\x0E\xAA~\x105\x99\\\x8C\xA7q\x1A=\xA9\x9D\xBAbx\xF5`[\x8Aw\x80\b\xE0vy\x00\x00\x00\x00\x00\x00\x00c\x00\x00\x00\x01\x00\x00\x00\x06foobar\x00\x00\x00\b\x00\x00\x00\x04root\x00\x00\x00\x00Xk\\\x1C\x00\x00\x00\x00ZK>g\x00\x00\x00#\x00\x00\x00\rforce-command\x00\x00\x00\x0E\x00\x00\x00\n/bin/false\x00\x00\x00c\x00\x00\x00\x15permit-X11-forwarding\x00\x00\x00\x00\x00\x00\x00\x16permit-port-forwarding\x00\x00\x00\x00\x00\x00\x00\npermit-pty\x00\x00\x00\x00\x00\x00\x00\x0Epermit-user-rc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x17\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+\x00\x00\x01\x0F\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".force_encoding('BINARY')
+CERT = "\x00\x00\x00\x1Cssh-rsa-cert-v01@openssh.com\x00\x00\x00 Ir\xB9\xC9\x94l\x0ER\xA1h\xF5\xFDx\xB2J\xC6g\eHS\xDD\x162\x86\xF1\x90%\\$rf\xAF\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\xB3R\xBC\xF8\xEA\xA30\x90\x87\x85\xF6m\x80\xFB\x7F\x96%\xC0h\x85$\x05\x05J\x9BE\xD9\xDE\x81\xC0\xC9\xC2\xC0\x0F'\xD1TR\xCBb\xCD\xD0o\xA0\x15Q\x8B\xF26t\xC9!8\x85\xD2\f'\xC6\x14u\x1De\x90qyXl\a\x06\xA7\xD0\xB8 \xE1\xB3IP\xDE\xB5\xBE\x19\x0E\x97-M\xFDJT\x81\xE2\x8E>\xCD\x18\x9CJz\x1C\xB5}LsO\xF3\xAC\xAA\r\xAB\xF9\xD4\x83\x8DQ\x82\xE7F\xA4\x9F\x1C\x9A\xC5\xC3Y\x84k\x86\ef\xD7\x84\xE3\v\rlG\x15ya\xB0=\xDF\x11\x8D\x0FtZ/p\xBB\xB7g\xF5\xEBF8\xF5\x05}}\xDB\xFA\xA34dw\xE5\x80\xBC!=\x0E\x96\x18\bF\x10\a{\xFF\x9D2\xCA\xAAnu\x82\x82\xBA-F\x8C\x12\xBB\x04+nh\xE9N\xAF\fe\x16\x00Q\x9C\x1C\xCB\x94\x02\x8CQ\xFB,H[\x96\xF1Z4\nY]@\xE0\bs\x9Bh\x0E\xAA~\x105\x99\\\x8C\xA7q\x1A=\xA9\x9D\xBAbx\xF5`[\x8Aw\x80\b\xE0vy\x00\x00\x00\x00\x00\x00\x00c\x00\x00\x00\x01\x00\x00\x00\x06foobar\x00\x00\x00\b\x00\x00\x00\x04root\x00\x00\x00\x00Xk\\\x1C\x00\x00\x00\x00ZK>g\x00\x00\x00#\x00\x00\x00\rforce-command\x00\x00\x00\x0E\x00\x00\x00\n/bin/false\x00\x00\x00c\x00\x00\x00\x15permit-X11-forwarding\x00\x00\x00\x00\x00\x00\x00\x16permit-port-forwarding\x00\x00\x00\x00\x00\x00\x00\npermit-pty\x00\x00\x00\x00\x00\x00\x00\x0Epermit-user-rc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x17\x00\x00\x00\assh-rsa\x00\x00\x00\x03\x01\x00\x01\x00\x00\x01\x01\x00\x9DRU\x0E\x83\x8Eb}\x81vOn\xCA\xBA\x01%\xFE\x87\x80b\xB5\x98R%\xA9(\xC1\xAE\xEFq|\x82L\xADQ?\x1D\xC6o\xB8\xD8pI\e\xFC\xF8\xFE^\xAD*\xA4u;\x99S\fc\x11\xBE\xFD\x047B\x1C\xF2h\xBA\xB1\xB0\n\x12F\e\x16\xF7Z\x8D\xD3\xF2f\xC0\x1C\xD8\xBE\xCC\x82\x85Qka$\xB6\xBD\x1C)\x85B\xAAf\xC8\xF3V*\xC3\x1C\xAA\xDC\xC3I\xDDe\xEFu\x02M\x12\x1A\xE2};he\x9D\xB5\xA47\xE4\x12\x8F\xE0\xF1\xA5\x91/\xFB\xEA\t\x0F \x1E\xB4B@+6\x1F\xBD\xA7\xA9u\x80\x19\xAA\xAC\xFFK\\F\x8C\xD9u\f?\xB9#[M\xDF\xB0\xFC\xE8\xF6J\x98\xA4\x99\x8F\xF9]\x88\x1D|A%\xAB\e\x0EN\xAA\xD3 \xCF\xA7}c\xDE\xF5\xBA4\xC8\xD2\x81(\x13\xB3\x94@fC\xDC\xDF\xFD\xA1\e$?\x13\xA9m\xEB*\xCA'\xB3\x19\x19\xF0\xD2\xB3P\x00\x96ou\xE90\xC4-\x1F\xCF\x1Aw\x034\xC6\xDF\xA7\x8C\xCA^Ix\x15\xFA\x9A+\x00\x00\x01\x0F\x00\x00\x00\assh-rsa\x00\x00\x01\x00I\b%\x01\xB2\xCC\x87\xD7\e\xC5\x88\x93|\x9D\xEC}\xA4\x86\xD7\xBB\xB6\xD3\x93\xFD\\\xC73\xC2*\aV\xA2\x81\x05J\x91\x9AEKV\n\xB4\xEB\xF3\xBC\xBAr\x16\xE5\x9A\xB9\xDC(0\xB4\x1C\x9F\"\x9E\xF9\x91\xD0\x1F\x9Cp\r*\xE3\x8A\xD3\xB9W$[OI\xD2\x8F8\x9B\xA4\x9E\xFFuGg\x00\xA5\xCD\r\xDB\x95\xEE)_\xC3\xBCi\xA2\xCC\r\x86\xFD\xE9\xE6\x188\x92\xFD\xCC\n\x98t\x8C\x16\xF4O\xF6\xD5\xD4\xB7\\\xB95\x19\xA3\xBBW\xF3\xF7r<\xE6\x8C\xFC\xE5\x9F\xBF\xE0\xBF\x06\xE7v\xF2\x8Ek\xA4\x02\xB6fMd\xA5e\x87\xE1\x93\xF5\x81\xCF\xDF\x88\xDC\a\xA2\e\xD5\xCA\x14\xB2>\xF4\x8F|\xE5-w\xF5\x85\xD0\xF1F((\xD1\xEEE&\x1D\xA2+\xEC\x93\xE7\xC7\xAE\xE38\xE4\xAE\xF7 \xED\xC6\r\xD6\x1A\xE1#<\xA2)j\xB3TA\\\xFF;\xC5\xA6Tu\xAAap\xDE\xF4\xF7 p\xCA\xD2\xBA\xDC\xCDv\x17\xC2\xBCQ\xDF\xAB7^\xA1G\x18\xB9\xB2F\x81\x9Fq\x92\xD3".dup.force_encoding('BINARY')
ED25519 = <<~EOF
-----BEGIN OPENSSH PRIVATE KEY-----
diff --git a/test/integration/test_cert_host_auth.rb b/test/integration/test_cert_host_auth.rb
new file mode 100644
index 0000000..fee5b2b
--- /dev/null
+++ b/test/integration/test_cert_host_auth.rb
@@ -0,0 +1,94 @@
+require_relative 'common'
+require 'fileutils'
+require 'tmpdir'
+require 'net/ssh'
+
+require 'timeout'
+
+# see Vagrantfile,playbook for env.
+# we're running as net_ssh_1 user password foo
+# and usually connecting to net_ssh_2 user password foo2pwd
+class TestCertHostAuth < NetSSHTest
+ include IntegrationTestHelpers
+
+ def setup_ssh_env(&block)
+ tmpdir do |dir|
+ cert_type = "rsa"
+ # cert_type = "ssh-ed25519"
+ host_key_type = "ecdsa"
+ # host_key_type = "ed25519"
+
+ # create a cert, and sign the host key
+ @cert = "#{dir}/ca"
+ sh "rm -rf #{@cert} #{@cert}.pub"
+ sh "ssh-keygen -t #{cert_type} -N '' -C 'ca@hosts.netssh' -f #{@cert} #{debug ? '' : '-q'}"
+ FileUtils.cp "/etc/ssh/ssh_host_#{host_key_type}_key.pub", "#{dir}/one.hosts.netssh.pub"
+ Dir.chdir(dir) do
+ sh "ssh-keygen -s #{@cert} -h -I one.hosts.netssh -n one.hosts.netssh #{debug ? '' : '-q'} #{dir}/one.hosts.netssh.pub"
+ sh "ssh-keygen -L -f one.hosts.netssh-cert.pub" if debug
+ end
+ signed_host_key = "/etc/ssh/ssh_host_#{host_key_type}_key-cert.pub"
+ sh "sudo cp -f #{dir}/one.hosts.netssh-cert.pub #{signed_host_key}"
+
+ # we don't use this for signing the cert
+ @badcert = "#{dir}/badca"
+ sh "rm -rf #{@badcert} #{@badcert}.pub"
+ sh "ssh-keygen -t #{cert_type} -N '' -C 'ca@hosts.netssh' -f #{@badcert} #{debug ? '' : '-q'}"
+ yield(cert_pub: "#{@cert}.pub", badcert_pub: "#{@badcert}.pub", signed_host_key: signed_host_key)
+ end
+ end
+
+ def debug
+ false
+ end
+
+ def test_host_should_match_when_host_key_was_signed_by_key
+ Tempfile.open('cert_kh') do |f|
+ setup_ssh_env do |params|
+ data = File.read(params[:cert_pub])
+ f.write("@cert-authority [*.hosts.netssh]:2200 #{data}")
+ f.close
+
+ config_lines = ["HostCertificate #{params[:signed_host_key]}"]
+ start_sshd_7_or_later(config: config_lines) do |_pid, port|
+ Timeout.timeout(500) do
+ # sleep 0.2
+ # sh "ssh -v -i ~/.ssh/id_ed25519 one.hosts.netssh -o UserKnownHostsFile=#{f.path} -p 2200"
+ ret = Net::SSH.start("one.hosts.netssh", "net_ssh_1", password: 'foopwd', port: port, verify_host_key: :always, user_known_hosts_file: [f.path]) do |ssh|
+ ssh.exec! "echo 'foo'"
+ end
+ assert_equal "foo\n", ret
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ sleep 0.25
+ retry
+ end
+ end
+ end
+ end
+ end
+
+ def test_with_other_pub_key_host_key_should_not_match
+ Tempfile.open('cert_kh') do |f|
+ setup_ssh_env do |params|
+ data = File.read(params[:badcert_pub])
+ f.write("@cert-authority [*.hosts.netssh]:2200 #{data}")
+ f.close
+
+ config_lines = ["HostCertificate #{params[:signed_host_key]}"]
+ start_sshd_7_or_later(config: config_lines) do |_pid, port|
+ Timeout.timeout(100) do
+ sleep 0.2
+ assert_raises(Net::SSH::HostKeyMismatch) do
+ Net::SSH.start("one.hosts.netssh", "net_ssh_1", password: 'foopwd', port: port, verify_host_key: :always, user_known_hosts_file: [f.path]) do |ssh|
+ ssh.exec! "echo 'foo'"
+ end
+ end
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ sleep 0.25
+ retry
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/test/integration/test_cert_user_auth.rb b/test/integration/test_cert_user_auth.rb
index b975d0a..596d150 100644
--- a/test/integration/test_cert_user_auth.rb
+++ b/test/integration/test_cert_user_auth.rb
@@ -14,7 +14,7 @@ unless ENV['NET_SSH_NO_ED25519']
Dir.mktmpdir do |dir|
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
- sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ sign_user_key('net_ssh_1', "#{dir}/id_rsa_ed25519.pub")
ret = Net::SSH.start("localhost", "net_ssh_1", keys: "#{dir}/id_rsa_ed25519") do |ssh|
ssh.exec! 'echo "hello from:$USER"'
@@ -27,7 +27,7 @@ unless ENV['NET_SSH_NO_ED25519']
Dir.mktmpdir do |dir|
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
- sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ sign_user_key('net_ssh_1', "#{dir}/id_rsa_ed25519.pub")
sh "mv #{dir}/id_rsa_ed25519-cert.pub #{dir}/cert"
ret = Net::SSH.start("localhost", "net_ssh_1", keys: "#{dir}/id_rsa_ed25519", keycerts: "#{dir}/cert") do |ssh|
@@ -42,7 +42,7 @@ unless ENV['NET_SSH_NO_ED25519']
with_agent do
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'"
- sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ sign_user_key('net_ssh_1', "#{dir}/id_rsa_ed25519.pub")
ssh_add("#{dir}/id_rsa_ed25519", "pwd")
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519-cert.pub"
@@ -61,7 +61,7 @@ unless ENV['NET_SSH_NO_ED25519']
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
# add key before signing cert
ssh_add("#{dir}/id_rsa_ed25519", "pwd")
- sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ sign_user_key('net_ssh_1', "#{dir}/id_rsa_ed25519.pub")
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
ret = Net::SSH.start("localhost", "net_ssh_1", keycerts: "#{dir}/id_rsa_ed25519-cert.pub") do |ssh|
diff --git a/test/integration/test_channel.rb b/test/integration/test_channel.rb
index d07e0a1..cd23c9e 100644
--- a/test/integration/test_channel.rb
+++ b/test/integration/test_channel.rb
@@ -25,7 +25,7 @@ class TestChannel < NetSSHTest
@key_id_rsa = "#{dir}/id_rsa"
sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub"
sh "ssh-keygen -q -f #{@key_id_rsa} -t rsa -N ''"
- set_authorized_key(user,"#{@key_id_rsa}.pub")
+ set_authorized_key(user, "#{@key_id_rsa}.pub")
yield
end
end
@@ -34,6 +34,7 @@ class TestChannel < NetSSHTest
ssh.open_channel do |channel|
channel.exec(command) do |_ch, success|
raise "could not execute command: #{command.inspect}" unless success
+
channel_success_handler.call
channel.on_data do |ch2, data|
yield(ch2, :stdout, data)
@@ -56,7 +57,7 @@ class TestChannel < NetSSHTest
system("killall /bin/nc")
end
channel = ssh_exec(ssh, "echo Begin ; sleep 100 ; echo End", channel_success_handler) do |ch, _type, data|
- ch[:result] ||= ""
+ ch[:result] ||= String.new
ch[:result] << data
end
assert_raises(IOError) { channel.wait }
@@ -77,7 +78,7 @@ class TestChannel < NetSSHTest
system("killall /bin/nc")
end
channel = ssh_exec(ssh, "echo Hello!", channel_success_handler) do |ch, _type, data|
- ch[:result] ||= ""
+ ch[:result] ||= "".dup
ch[:result] << data
end
channel.wait
@@ -107,31 +108,29 @@ class TestChannel < NetSSHTest
def test_channel_should_set_environment_variables_on_remote
setup_ssh_env do
- start_sshd_7_or_later(config: 'AcceptEnv *') do |_pid, port|
- Timeout.timeout(4) do
- begin
- # We have our own sshd, give it a chance to come up before
- # listening.
- proxy = Net::SSH::Proxy::Command.new("/bin/nc localhost #{port}")
- res = nil
- Net::SSH.start(*ssh_start_params(port: port, proxy: proxy, set_env: { foo: 'bar', baz: 'whale will' })) do |ssh|
- channel_success_handler = lambda do
- sleep(0.1)
- system("killall /bin/nc")
- end
- channel = ssh_exec(ssh, "echo $foo; echo $baz", channel_success_handler) do |ch, _type, data|
- ch[:result] ||= ""
- ch[:result] << data
- end
- channel.wait
- res = channel[:result]
- assert_equal(res, "bar\nwhale will\n")
+ start_sshd_7_or_later(config: ['AcceptEnv foo baz']) do |_pid, port|
+ Timeout.timeout(20) do
+ # We have our own sshd, give it a chance to come up before
+ # listening.
+ proxy = Net::SSH::Proxy::Command.new("/bin/nc localhost #{port}")
+ res = nil
+ Net::SSH.start(*ssh_start_params(port: port, proxy: proxy, set_env: { foo: 'bar', baz: 'whale will' })) do |ssh|
+ channel_success_handler = lambda do
+ sleep(0.1)
+ system("killall /bin/nc")
+ end
+ channel = ssh_exec(ssh, "echo A:$foo; echo B:$baz", channel_success_handler) do |ch, _type, data|
+ ch[:result] ||= String.new
+ ch[:result] << data
end
- assert_equal(res, "bar\nwhale will\n")
- rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError
- sleep 0.25
- retry
+ channel.wait
+ res = channel[:result]
+ assert_equal(res, "A:bar\nB:whale will\n")
end
+ assert_equal(res, "A:bar\nB:whale will\n")
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError
+ sleep 0.25
+ retry
end
end
end
diff --git a/test/integration/test_curve25519sha256.rb b/test/integration/test_curve25519sha256.rb
index e2e38c2..e6a152b 100644
--- a/test/integration/test_curve25519sha256.rb
+++ b/test/integration/test_curve25519sha256.rb
@@ -12,7 +12,6 @@ unless ENV['NET_SSH_NO_ED25519']
# and usually connecting to net_ssh_2 user password foo2pwd
class TestCurve25519Sha256Keys < NetSSHTest
include IntegrationTestHelpers
-
def test_with_only_curve_kex
config_lines = File.read('/etc/ssh/sshd_config').split("\n")
@@ -29,21 +28,19 @@ unless ENV['NET_SSH_NO_ED25519']
f.close
start_sshd_7_or_later(config: config_lines) do |_pid, port|
Timeout.timeout(4) do
- begin
- # We have our own sshd, give it a chance to come up before
- # listening.
- ret = Net::SSH.start("localhost", "net_ssh_1", password: 'foopwd', port: port, user_known_hosts_file: [f.path]) do |ssh|
- assert_equal ssh.transport.algorithms.kex, "curve25519-sha256"
- ssh.exec! "echo 'foo'"
- end
- assert_equal "foo\n", ret
- rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
- sleep 0.25
- retry
+ # We have our own sshd, give it a chance to come up before
+ # listening.
+ ret = Net::SSH.start("localhost", "net_ssh_1", password: 'foopwd', port: port, user_known_hosts_file: [f.path]) do |ssh|
+ assert_equal ssh.transport.algorithms.kex, "curve25519-sha256"
+ ssh.exec! "echo 'foo'"
end
+ assert_equal "foo\n", ret
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ sleep 0.25
+ retry
end
end
end
end
end
-end \ No newline at end of file
+end
diff --git a/test/integration/test_ed25519_pkeys.rb b/test/integration/test_ed25519_pkeys.rb
index d42cbfd..0017801 100644
--- a/test/integration/test_ed25519_pkeys.rb
+++ b/test/integration/test_ed25519_pkeys.rb
@@ -10,31 +10,31 @@ unless ENV['NET_SSH_NO_ED25519']
# and usually connecting to net_ssh_2 user password foo2pwd
class TestED25519PKeys < NetSSHTest
include IntegrationTestHelpers
-
+
def test_in_file_no_password
Dir.mktmpdir do |dir|
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa_ed25519.pub")
ret = Net::SSH.start("localhost", "net_ssh_1", { keys: "#{dir}/id_rsa_ed25519" }) do |ssh|
ssh.exec! 'echo "hello from:$USER"'
end
assert_equal "hello from:net_ssh_1\n", ret
end
- end
-
+ end
+
def test_ssh_agent
Dir.mktmpdir do |dir|
with_agent do
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
- ssh_add("#{dir}/id_rsa_ed25519","pwd")
-
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa_ed25519.pub")
+ ssh_add("#{dir}/id_rsa_ed25519", "pwd")
+
# TODO: fix bug in net ssh which reads public key even if private key is there
sh "mv #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519.pub.hidden"
-
+
ret = Net::SSH.start("localhost", "net_ssh_1") do |ssh|
ssh.exec! 'echo "hello from:$USER"'
end
@@ -42,23 +42,23 @@ unless ENV['NET_SSH_NO_ED25519']
end
end
end
-
+
def test_in_file_with_password
Dir.mktmpdir do |dir|
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
-
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa_ed25519.pub")
+
# TODO: fix bug in net ssh which reads public key even if private key is there
sh "mv #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519.pub.hidden"
- ret = Net::SSH.start("localhost", "net_ssh_1", { keys: "#{dir}/id_rsa_ed25519", passphrase:'pwd' }) do |ssh|
+ ret = Net::SSH.start("localhost", "net_ssh_1", { keys: "#{dir}/id_rsa_ed25519", passphrase: 'pwd' }) do |ssh|
ssh.exec! 'echo "hello from:$USER"'
end
assert_equal "hello from:net_ssh_1\n", ret
end
end
-
+
def test_with_only_ed25519_host_key
config_lines = File.read('/etc/ssh/sshd_config').split("\n")
config_lines = config_lines.map do |line|
@@ -68,7 +68,7 @@ unless ENV['NET_SSH_NO_ED25519']
line
end
end
-
+
Tempfile.open('empty_kh') do |f|
f.close
with_sshd_config(config_lines.join("\n")) do
diff --git a/test/integration/test_encoding.rb b/test/integration/test_encoding.rb
index febdfba..9396e22 100644
--- a/test/integration/test_encoding.rb
+++ b/test/integration/test_encoding.rb
@@ -20,4 +20,4 @@ class TestEncoding < NetSSHTest
end
assert_equal ret, "#{string}\n"
end
-end \ No newline at end of file
+end
diff --git a/test/integration/test_forward.rb b/test/integration/test_forward.rb
index 3ff76cd..f006e2d 100644
--- a/test/integration/test_forward.rb
+++ b/test/integration/test_forward.rb
@@ -33,7 +33,7 @@ class ForwardTestBase < NetSSHTest
end
def ssh_start_params(options = {})
- [localhost,user, { keys: @key_id_rsa }.merge(options)]
+ [localhost, user, { keys: @key_id_rsa }.merge(options)]
end
def setup_ssh_env(&block)
@@ -41,7 +41,7 @@ class ForwardTestBase < NetSSHTest
@key_id_rsa = "#{dir}/id_rsa"
sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub"
sh "ssh-keygen -q -f #{@key_id_rsa} -t rsa -N ''"
- set_authorized_key(user,"#{@key_id_rsa}.pub")
+ set_authorized_key(user, "#{@key_id_rsa}.pub")
yield
end
end
@@ -51,15 +51,13 @@ class ForwardTestBase < NetSSHTest
Thread.start do
loop do
Thread.start(server.accept) do |client|
- begin
- 10000.times do |i|
- client.puts "item#{i}"
- end
- client.close
- rescue StandardError
- exceptions << $!
- raise
+ 10000.times do |i|
+ client.puts "item#{i}"
end
+ client.close
+ rescue StandardError
+ exceptions << $!
+ raise
end
end
end
@@ -68,19 +66,17 @@ class ForwardTestBase < NetSSHTest
end
class TestForward < ForwardTestBase
- def start_server_closing_soon(exceptions=nil)
+ def start_server_closing_soon(exceptions = nil)
server = TCPServer.open(0)
Thread.start do
loop do
Thread.start(server.accept) do |client|
- begin
- client.recv(1024)
- client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
- client.close
- rescue StandardError
- exceptions << $!
- raise
- end
+ client.recv(1024)
+ client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
+ client.close
+ rescue StandardError
+ exceptions << $!
+ raise
end
end
end
@@ -187,14 +183,12 @@ class TestForward < ForwardTestBase
session.forward.local(local_port, localhost, remote_port)
client_done = Queue.new
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- client.recv(1024)
- client.close
- sleep(0.2)
- ensure
- client_done << true
- end
+ client = TCPSocket.new(localhost, local_port)
+ client.recv(1024)
+ client.close
+ sleep(0.2)
+ ensure
+ client_done << true
end
session.loop(0.1) { client_done.empty? }
assert_equal "Broken pipe", server_exc.pop.to_s unless server_exc.empty?
@@ -211,15 +205,13 @@ class TestForward < ForwardTestBase
session.forward.local(local_port, localhost, remote_port)
client_done = Queue.new
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- client.recv(1024)
- client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
- client.close
- sleep(0.1)
- ensure
- client_done << true
- end
+ client = TCPSocket.new(localhost, local_port)
+ client.recv(1024)
+ client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
+ client.close
+ sleep(0.1)
+ ensure
+ client_done << true
end
session.loop(0.1) { client_done.empty? }
assert_equal "Broken pipe", server_exc.pop.to_s unless server_exc.empty?
@@ -235,16 +227,14 @@ class TestForward < ForwardTestBase
session.forward.local(local_port, localhost, remote_port)
client_done = Queue.new
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- 1.times do |i|
- client.puts "item#{i}"
- end
- client.close
- sleep(0.1)
- ensure
- client_done << true
+ client = TCPSocket.new(localhost, local_port)
+ 1.times do |i|
+ client.puts "item#{i}"
end
+ client.close
+ sleep(0.1)
+ ensure
+ client_done << true
end
session.loop(0.1) { client_done.empty? }
end
@@ -268,31 +258,27 @@ class TestForward < ForwardTestBase
session = Net::SSH.start(*ssh_start_params)
server_done = Queue.new
server = start_server do |client|
- begin
- data = client.read message.size
- server_done << data
- client.close
- rescue StandardError
- server_done << $!
- end
+ data = client.read message.size
+ server_done << data
+ client.close
+ rescue StandardError
+ server_done << $!
end
client_done = Queue.new
got_remote_port = Queue.new
local_port = server.addr[1]
- session.forward.remote(0, localhost, local_port, localhost) do |actual_remote_port|
+ session.forward.remote(local_port, localhost, 0, localhost) do |actual_remote_port|
got_remote_port << actual_remote_port
end
session.loop(0.1) { got_remote_port.empty? }
remote_port = got_remote_port.pop
Thread.start do
- begin
- client = TCPSocket.new(localhost, remote_port)
- client.write(message)
- client.close
- client_done << true
- rescue StandardError
- client_done << $!
- end
+ client = TCPSocket.new(localhost, remote_port)
+ client.write(message)
+ client.close
+ client_done << true
+ rescue StandardError
+ client_done << $!
end
Timeout.timeout(5) do
session.loop(0.1) { server_done.empty? }
@@ -302,13 +288,13 @@ class TestForward < ForwardTestBase
end
class TCPProxy
- def initialize()
+ def initialize
@sockets = []
end
attr_reader :sockets
def open(host, port, connection_options = nil)
- socket = TCPSocket.new(host,port)
+ socket = TCPSocket.new(host, port)
@sockets << socket
socket
end
@@ -333,25 +319,21 @@ class TestForward < ForwardTestBase
# read on forwarded port
client_done = Queue.new
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- client.read(6)
- proxy.close_all
- client.read(7)
- client.close
- client_done << true
- rescue StandardError
- client_done << $!
- end
+ client = TCPSocket.new(localhost, local_port)
+ client.read(6)
+ proxy.close_all
+ client.read(7)
+ client.close
+ client_done << true
+ rescue StandardError
+ client_done << $!
end
server_error = nil
Timeout.timeout(5) do
- begin
- session.loop(0.1) { true }
- rescue IOError, Errno::EBADF
- server_error = $!
- # puts "Error: #{$!} #{$!.backtrace.join("\n")}"
- end
+ session.loop(0.1) { true }
+ rescue IOError, Errno::EBADF
+ server_error = $!
+ # puts "Error: #{$!} #{$!.backtrace.join("\n")}"
end
begin
Timeout.timeout(5) do
@@ -379,16 +361,14 @@ class TestForward < ForwardTestBase
# read on forwarded port
client_done = Queue.new
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- client.read(6)
- system("killall /bin/nc")
- client.read(7)
- client.close
- client_done << true
- rescue StandardError
- client_done << $!
- end
+ client = TCPSocket.new(localhost, local_port)
+ client.read(6)
+ system("killall /bin/nc")
+ client.read(7)
+ client.close
+ client_done << true
+ rescue StandardError
+ client_done << $!
end
Timeout.timeout(5) do
begin
@@ -411,26 +391,22 @@ class TestForward < ForwardTestBase
session = Net::SSH.start(*ssh_start_params)
server_done = Queue.new
server = start_server do |client|
- begin
- data = client.read message.size
- server_done << data
- client.close
- rescue StandardError
- server_done << $!
- end
+ data = client.read message.size
+ server_done << data
+ client.close
+ rescue StandardError
+ server_done << $!
end
client_done = Queue.new
remote_port = server.addr[1]
local_port = session.forward.local(0, localhost, remote_port)
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- client.write(message)
- client.close
- client_done << true
- rescue StandardError
- client_done << $!
- end
+ client = TCPSocket.new(localhost, local_port)
+ client.write(message)
+ client.close
+ client_done << true
+ rescue StandardError
+ client_done << $!
end
Timeout.timeout(5) do
session.loop(0.1) { server_done.empty? }
@@ -442,7 +418,7 @@ class TestForward < ForwardTestBase
def test_server_eof_should_be_handled_remote
setup_ssh_env do
message = "This is a small message!"
- session = Net::SSH.start(*ssh_start_params)
+ session = Net::SSH.start(*ssh_start_params(verbose: :debug))
server = start_server do |client|
client.write message
client.close
@@ -450,20 +426,21 @@ class TestForward < ForwardTestBase
client_done = Queue.new
got_remote_port = Queue.new
local_port = server.addr[1]
- session.forward.remote(0, localhost, local_port, localhost) do |actual_remote_port|
+ puts "LOCAL PORT: #{local_port}"
+ session.forward.remote(local_port, localhost, 0, localhost) do |actual_remote_port|
got_remote_port << actual_remote_port
end
session.loop(0.1) { got_remote_port.empty? }
remote_port = got_remote_port.pop
+ puts "Remote port:#{remote_port}"
Thread.start do
- begin
- client = TCPSocket.new(localhost, remote_port)
- data = client.read(4096)
- client.close
- client_done << data
- rescue StandardError
- client_done << $!
- end
+ client = TCPSocket.new(localhost, remote_port)
+ data = client.read(4096)
+ client.close
+ client_done << data
+ puts "Received: #{data}"
+ rescue StandardError
+ client_done << $!
end
Timeout.timeout(5) do
session.loop(0.1) { client_done.empty? }
@@ -484,14 +461,12 @@ class TestForward < ForwardTestBase
remote_port = server.addr[1]
local_port = session.forward.local(0, localhost, remote_port)
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- data = client.read(4096)
- client.close
- client_done << data
- rescue StandardError
- client_done << $!
- end
+ client = TCPSocket.new(localhost, local_port)
+ data = client.read(4096)
+ client.close
+ client_done << data
+ rescue StandardError
+ client_done << $!
end
Timeout.timeout(5) do
session.loop(0.1) { client_done.empty? }
@@ -502,14 +477,12 @@ class TestForward < ForwardTestBase
def _run_reading_client(client_done, local_port)
Thread.start do
- begin
- client = TCPSocket.new(localhost, local_port)
- data = client.read(4096)
- client.close
- client_done << data
- rescue StandardError
- client_done << $!
- end
+ client = TCPSocket.new(localhost, local_port)
+ data = client.read(4096)
+ client.close
+ client_done << data
+ rescue StandardError
+ client_done << $!
end
end
@@ -621,14 +594,12 @@ class TestForwardOnUnixSockets < ForwardTestBase
client_done = Queue.new
Thread.start do
- begin
- client = UNIXSocket.new(local_socket.path)
- client_data = client.recv(1024)
- client.close
- sleep(0.2)
- ensure
- client_done << true
- end
+ client = UNIXSocket.new(local_socket.path)
+ client_data = client.recv(1024)
+ client.close
+ sleep(0.2)
+ ensure
+ client_done << true
end
begin
@@ -646,16 +617,15 @@ class TestForwardOnUnixSockets < ForwardTestBase
def test_forward_local_unix_socket_to_remote_socket
setup_ssh_env do
start_sshd_7_or_later do |_pid, port|
- session = Timeout.timeout(4) do
- begin
- # We have our own sshd, give it a chance to come up before
- # listening.
+ session =
+ # We have our own sshd, give it a chance to come up before
+ # listening.
+ Timeout.timeout(4) do
Net::SSH.start(*ssh_start_params(port: port))
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
sleep 0.25
retry
end
- end
create_local_socket do |remote_socket|
# Make sure sshd can 'rw'.
diff --git a/test/integration/test_hmac_etm.rb b/test/integration/test_hmac_etm.rb
index 3254289..1111a26 100644
--- a/test/integration/test_hmac_etm.rb
+++ b/test/integration/test_hmac_etm.rb
@@ -30,29 +30,27 @@ class TestHMacEtm < NetSSHTest
config_lines.push("MACs #{macs}")
end
- variants.each do |key,variant|
+ variants.each do |key, variant|
define_method "test_with_only_hmac_etm#{key}" do
start_sshd_7_or_later(config: config_with_macs(variant)) do |_pid, port|
Timeout.timeout(4) do
- begin
- # We have our own sshd, give it a chance to come up before
- # listening.
- ret = Net::SSH.start(
- "localhost",
- "net_ssh_1",
- password: 'foopwd',
- port: port,
- hmac: [variant]
- ) do |ssh|
- assert_equal ssh.transport.algorithms.hmac_client, variant
- assert_equal ssh.transport.algorithms.hmac_server, variant
- ssh.exec! "echo 'foo123'"
- end
- assert_equal "foo123\n", ret
- rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
- sleep 0.25
- retry
+ # We have our own sshd, give it a chance to come up before
+ # listening.
+ ret = Net::SSH.start(
+ "localhost",
+ "net_ssh_1",
+ password: 'foopwd',
+ port: port,
+ hmac: [variant]
+ ) do |ssh|
+ assert_equal ssh.transport.algorithms.hmac_client, variant
+ assert_equal ssh.transport.algorithms.hmac_server, variant
+ ssh.exec! "echo 'foo123'"
end
+ assert_equal "foo123\n", ret
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ sleep 0.25
+ retry
end
end
end
@@ -80,4 +78,4 @@ class TestHMacEtm < NetSSHTest
ssh.close
end
end
-end \ No newline at end of file
+end
diff --git a/test/integration/test_http_proxy.rb b/test/integration/test_http_proxy.rb
index bfde488..a59eb60 100644
--- a/test/integration/test_http_proxy.rb
+++ b/test/integration/test_http_proxy.rb
@@ -31,7 +31,7 @@ class TestHTTPProxy < NetSSHTest
@key_id_rsa = "#{dir}/id_rsa"
sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub"
sh "ssh-keygen -q -f #{@key_id_rsa} -t rsa -N ''"
- set_authorized_key(user,"#{@key_id_rsa}.pub")
+ set_authorized_key(user, "#{@key_id_rsa}.pub")
yield
end
end
@@ -80,4 +80,4 @@ class TestHTTPProxy < NetSSHTest
end
end
end
-end \ No newline at end of file
+end
diff --git a/test/integration/test_id_rsa_keys.rb b/test/integration/test_id_rsa_keys.rb
index 84d6728..44894cc 100644
--- a/test/integration/test_id_rsa_keys.rb
+++ b/test/integration/test_id_rsa_keys.rb
@@ -14,7 +14,7 @@ class TestIDRSAPKeys < NetSSHTest
tmpdir do |dir|
sh "rm -rf #{dir}/id_rsa #{dir}/id_rsa.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa -t rsa -N ''"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa.pub")
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa.pub")
ret = Net::SSH.start("localhost", "net_ssh_1", { keys: "#{dir}/id_rsa" }) do |ssh|
ssh.exec! 'echo "hello from:$USER"'
@@ -29,8 +29,8 @@ class TestIDRSAPKeys < NetSSHTest
with_agent do
sh "rm -rf #{dir}/id_rsa #{dir}/id_rsa.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa -t rsa -N 'pwd123'"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa.pub")
- ssh_add("#{dir}/id_rsa","pwd123")
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa.pub")
+ ssh_add("#{dir}/id_rsa", "pwd123")
ret = Net::SSH.start("localhost", "net_ssh_1") do |ssh|
ssh.exec! 'echo "hello from:$USER"'
@@ -45,8 +45,8 @@ class TestIDRSAPKeys < NetSSHTest
with_agent do
sh "rm -rf #{dir}/id_rsa #{dir}/id_rsa.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa -t rsa -N 'pwd123'"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa.pub")
- ssh_add("#{dir}/id_rsa","pwd123")
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa.pub")
+ ssh_add("#{dir}/id_rsa", "pwd123")
ret = Net::SSH.start("localhost", "net_ssh_1", keys: ["#{dir}/id_rsa"]) do |ssh|
ssh.exec! 'echo "hello from:$USER"'
@@ -60,7 +60,7 @@ class TestIDRSAPKeys < NetSSHTest
tmpdir do |dir|
sh "rm -rf #{dir}/id_rsa #{dir}/id_rsa.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa -t rsa -N 'pwd12'"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa.pub")
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa.pub")
ret = Net::SSH.start("localhost", "net_ssh_1", { keys: "#{dir}/id_rsa", passphrase: 'pwd12' }) do |ssh|
ssh.exec! 'echo "hello from:$USER"'
@@ -74,7 +74,7 @@ class TestIDRSAPKeys < NetSSHTest
tmpdir do |dir|
sh "rm -rf #{dir}/id_rsa #{dir}/id_rsa.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa -t rsa -N 'pwd12'"
- set_authorized_key('net_ssh_1',"#{dir}/id_rsa.pub")
+ set_authorized_key('net_ssh_1', "#{dir}/id_rsa.pub")
private_key = File.read("#{dir}/id_rsa")
options = { keys: [], key_data: [private_key] }
diff --git a/test/integration/test_proxy.rb b/test/integration/test_proxy.rb
index d73b7ba..6572c42 100644
--- a/test/integration/test_proxy.rb
+++ b/test/integration/test_proxy.rb
@@ -3,6 +3,7 @@ require 'net/ssh/buffer'
require 'net/ssh'
require 'timeout'
require 'tempfile'
+require 'fileutils'
require 'net/ssh/proxy/command'
require 'net/ssh/proxy/jump'
@@ -18,7 +19,7 @@ class TestProxy < NetSSHTest
end
def ssh_start_params(options)
- [localhost,user, { keys: @key_id_rsa }.merge(options)]
+ [localhost, user, { keys: @key_id_rsa }.merge(options)]
end
def setup_ssh_env(&block)
@@ -26,7 +27,7 @@ class TestProxy < NetSSHTest
@key_id_rsa = "#{dir}/id_rsa"
sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub"
sh "ssh-keygen -q -f #{@key_id_rsa} -t rsa -N ''"
- set_authorized_key(user,"#{@key_id_rsa}.pub")
+ set_authorized_key(user, "#{@key_id_rsa}.pub")
yield
end
end
@@ -38,11 +39,12 @@ class TestProxy < NetSSHTest
@gwkey_id_rsa = "#{dir}/id_rsa"
sh "rm -rf #{@gwkey_id_rsa} #{@gwkey_id_rsa}.pub"
sh "ssh-keygen -q -f #{@gwkey_id_rsa} -t rsa -N ''"
- set_authorized_key(gwuser,"#{@gwkey_id_rsa}.pub")
+ set_authorized_key(gwuser, "#{@gwkey_id_rsa}.pub")
config = "Host #{gwhost}
IdentityFile #{@gwkey_id_rsa}
StrictHostKeyChecking no
"
+ FileUtils.mkdir_p File.expand_path("~/.ssh")
my_config = File.expand_path("~/.ssh/config")
File.open(my_config, 'w') { |file| file.write(config) }
begin
@@ -65,7 +67,7 @@ class TestProxy < NetSSHTest
end
end
- def with_spurious_write_wakeup_emulate(rate=99,&block)
+ def with_spurious_write_wakeup_emulate(rate = 99, &block)
orig_io_select = IO.method(:select)
count = 0
@@ -73,7 +75,7 @@ class TestProxy < NetSSHTest
count += 1
if (count % rate != 0)
if params && params[1] && !params[1].empty?
- return [[],params[1],[]]
+ return [[], params[1], []]
end
end
orig_io_select.call(*params)
@@ -97,7 +99,7 @@ class TestProxy < NetSSHTest
ok = Net::SSH.start(*ssh_start_params(proxy: proxy)) do |ssh|
with_spurious_write_wakeup_emulate do
ret = ssh.exec! "echo \"$USER:#{large_msg}\""
- assert_equal "/bin/sh: Argument list too long\n", ret
+ assert_match(%r{/bin/.*sh: Argument list too long\n}, ret)
hello_count = 1000
ret = ssh.exec! "ruby -e 'puts \"Hello\"*#{hello_count}'"
assert_equal "Hello" * hello_count + "\n", ret
@@ -137,6 +139,7 @@ class TestProxy < NetSSHTest
@io
end
end
+
def test_does_close_proxy_on_proxy_failure
setup_ssh_env do
proxy = DbgProxy.new(Net::SSH::Proxy::Command.new('sleep 2 && ssh -W %h:%p -o "PreferredAuthentications none" user@localhost'))
diff --git a/test/manual/test_pageant.rb b/test/manual/test_pageant.rb
index 0f8b591..b07e82c 100644
--- a/test/manual/test_pageant.rb
+++ b/test/manual/test_pageant.rb
@@ -15,7 +15,6 @@ require_relative '../common'
require 'net/ssh/authentication/agent'
module Authentication
-
class TestPageapnt < NetSSHTest
def test_agent_should_be_able_to_negotiate
begin
@@ -29,7 +28,7 @@ module Authentication
private
- def agent(auto=:connect)
+ def agent(auto = :connect)
@agent ||= begin
agent = Net::SSH::Authentication::Agent.new
agent.connect! if auto == :connect
@@ -37,5 +36,4 @@ module Authentication
end
end
end
-
end
diff --git a/test/start/test_transport.rb b/test/start/test_transport.rb
index fcf1c4e..e94f32b 100644
--- a/test/start/test_transport.rb
+++ b/test/start/test_transport.rb
@@ -5,19 +5,19 @@ module NetSSH
class TestStart < NetSSHTest
attr_reader :transport_session
attr_reader :authentication_session
-
+
def setup
@transport_session = mock('transport_session')
@authentication_session = mock('authentication_session')
Net::SSH::Transport::Session.expects(new: transport_session)
Net::SSH::Authentication::Session.expects(new: authentication_session)
end
-
+
def test_close_transport_when_authentication_fails
authentication_session.expects(authenticate: false)
-
+
transport_session.expects(:close).at_least_once
-
+
begin
Net::SSH.start('localhost', 'testuser') {}
rescue Net::SSH::AuthenticationFailed
@@ -25,4 +25,4 @@ module NetSSH
end
end
end
-end \ No newline at end of file
+end
diff --git a/test/start/test_user_nil.rb b/test/start/test_user_nil.rb
index ff2cd59..aea4efa 100644
--- a/test/start/test_user_nil.rb
+++ b/test/start/test_user_nil.rb
@@ -18,7 +18,7 @@ module NetSSH
end
def test_start_should_use_default_user_when_nil
- @authentication_session.stubs(:authenticate).with {|_next_service, user, _password| user == Etc.getpwuid.name }.returns(true)
+ @authentication_session.stubs(:authenticate).with { |_next_service, user, _password| user == Etc.getpwuid.name }.returns(true)
assert_nothing_raised do
Net::SSH.start('localhost', nil, config: false)
end
diff --git a/test/test/test_test.rb b/test/test/test_test.rb
index a1dc4f4..d2b8894 100644
--- a/test/test/test_test.rb
+++ b/test/test/test_test.rb
@@ -73,4 +73,4 @@ class TestNetSSHTest < NetSSHTest
connection.loop
end
end
-end \ No newline at end of file
+end
diff --git a/test/test_all.rb b/test/test_all.rb
index c4df9b4..0d060d3 100644
--- a/test/test_all.rb
+++ b/test/test_all.rb
@@ -9,4 +9,4 @@ Dir.chdir(File.dirname(__FILE__)) do
test_files = test_files.select { |f| f =~ Regexp.new(ENV['ONLY']) } if ENV['ONLY']
test_files = test_files.reject { |f| f =~ Regexp.new(ENV['EXCEPT']) } if ENV['EXCEPT']
test_files.each { |file| require(file) }
-end \ No newline at end of file
+end
diff --git a/test/test_buffer.rb b/test/test_buffer.rb
index e1fcbd2..c4fc9f2 100644
--- a/test/test_buffer.rb
+++ b/test/test_buffer.rb
@@ -1,4 +1,5 @@
# encoding: ASCII-8BIT
+# frozen_string_literal: false
require_relative 'common'
require 'net/ssh/buffer'
@@ -55,7 +56,7 @@ class TestBuffer < NetSSHTest
end
def test_from_with_array_argument_should_write_multiple_of_the_given_type
- buffer = Net::SSH::Buffer.from(:byte, [1,2,3,4,5])
+ buffer = Net::SSH::Buffer.from(:byte, [1, 2, 3, 4, 5])
assert_equal "\1\2\3\4\5", buffer.to_s
end
diff --git a/test/test_buffered_io.rb b/test/test_buffered_io.rb
index eefe7f9..1002686 100644
--- a/test/test_buffered_io.rb
+++ b/test/test_buffered_io.rb
@@ -60,4 +60,4 @@ class TestBufferedIo < NetSSHTest
io
end
end
-end \ No newline at end of file
+end
diff --git a/test/test_config.rb b/test/test_config.rb
index f71a952..82c2377 100644
--- a/test/test_config.rb
+++ b/test/test_config.rb
@@ -122,29 +122,29 @@ class TestConfig < NetSSHTest
def test_translate_should_correctly_translate_from_openssh_to_net_ssh_names
open_ssh = {
- 'bindaddress' => "127.0.0.1",
- 'ciphers' => "a,b,c",
- 'compression' => true,
- 'compressionlevel' => 6,
- 'connecttimeout' => 100,
- 'forwardagent' => true,
+ 'bindaddress' => "127.0.0.1",
+ 'ciphers' => "a,b,c",
+ 'compression' => true,
+ 'compressionlevel' => 6,
+ 'connecttimeout' => 100,
+ 'forwardagent' => true,
'hostbasedauthentication' => true,
- 'hostkeyalgorithms' => "d,e,f",
- 'identityfile' => %w(g h i),
- 'macs' => "j,k,l",
- 'certificatefile' => %w(m n o),
- 'passwordauthentication' => true,
- 'port' => 1234,
- 'pubkeyauthentication' => true,
- 'rekeylimit' => 1024,
- 'sendenv' => "LC_*",
- 'setenv' => 'foo="bar" baz=whale cat="black hole"',
+ 'hostkeyalgorithms' => "d,e,f",
+ 'identityfile' => %w(g h i),
+ 'macs' => "j,k,l",
+ 'certificatefile' => %w(m n o),
+ 'passwordauthentication' => true,
+ 'port' => 1234,
+ 'pubkeyauthentication' => true,
+ 'rekeylimit' => 1024,
+ 'sendenv' => "LC_*",
+ 'setenv' => 'foo="bar" baz=whale cat="black hole"',
'numberofpasswordprompts' => '123',
- 'serveraliveinterval' => '2',
- 'serveralivecountmax' => '4',
- 'fingerprinthash' => 'MD5',
- 'userknownhostsfile' => '/dev/null',
- 'stricthostkeychecking' => false
+ 'serveraliveinterval' => '2',
+ 'serveralivecountmax' => '4',
+ 'fingerprinthash' => 'MD5',
+ 'userknownhostsfile' => '/dev/null',
+ 'stricthostkeychecking' => false
}
net_ssh = Net::SSH::Config.translate(open_ssh)
@@ -170,16 +170,32 @@ class TestConfig < NetSSHTest
assert_equal 'MD5', net_ssh[:fingerprint_hash]
assert_equal true, net_ssh[:keepalive]
assert_equal '/dev/null', net_ssh[:user_known_hosts_file]
- assert_equal false, net_ssh[:strict_host_key_checking]
+ assert_equal :never, net_ssh[:verify_host_key]
+ end
+
+ def test_translate_should_turn_on_host_key_verification
+ open_ssh = { 'stricthostkeychecking' => true }
+
+ net_ssh = Net::SSH::Config.translate(open_ssh)
+
+ assert_equal :always, net_ssh[:verify_host_key]
+ end
+
+ def test_translate_should_accept_new_host_key
+ open_ssh = { 'stricthostkeychecking' => 'accept-new' }
+
+ net_ssh = Net::SSH::Config.translate(open_ssh)
+
+ assert_equal :accept_new, net_ssh[:verify_host_key]
end
def test_translate_should_turn_off_authentication_methods
open_ssh = {
- 'hostbasedauthentication' => false,
- 'passwordauthentication' => false,
- 'pubkeyauthentication' => false,
+ 'hostbasedauthentication' => false,
+ 'passwordauthentication' => false,
+ 'pubkeyauthentication' => false,
'challengeresponseauthentication' => false,
- 'kbdinteractiveauthentication' => false
+ 'kbdinteractiveauthentication' => false
}
net_ssh = Net::SSH::Config.translate(open_ssh)
@@ -189,11 +205,11 @@ class TestConfig < NetSSHTest
def test_translate_should_turn_on_authentication_methods
open_ssh = {
- 'hostbasedauthentication' => true,
- 'passwordauthentication' => true,
- 'pubkeyauthentication' => true,
+ 'hostbasedauthentication' => true,
+ 'passwordauthentication' => true,
+ 'pubkeyauthentication' => true,
'challengeresponseauthentication' => true,
- 'kbdinteractiveauthentication' => true
+ 'kbdinteractiveauthentication' => true
}
net_ssh = Net::SSH::Config.translate(open_ssh)
@@ -202,9 +218,7 @@ class TestConfig < NetSSHTest
end
def test_translate_should_not_disable_keyboard_interactive_when_challange_or_keyboardinterective_is_on
- open_ssh = {
- 'kbdinteractiveauthentication' => false
- }
+ open_ssh = { 'kbdinteractiveauthentication' => false }
net_ssh = Net::SSH::Config.translate(open_ssh)
assert_equal %w(keyboard-interactive none password publickey), net_ssh[:auth_methods].sort
@@ -529,7 +543,7 @@ class TestConfig < NetSSHTest
private
- def with_home_env(value,&block)
+ def with_home_env(value, &block)
env_home_before = ENV['HOME']
begin
ENV['HOME'] = value
diff --git a/test/test_key_factory.rb b/test/test_key_factory.rb
index 2a92a08..c6f7705 100644
--- a/test/test_key_factory.rb
+++ b/test/test_key_factory.rb
@@ -65,7 +65,7 @@ class TestKeyFactory < NetSSHTest
def test_load_encrypted_private_key_should_give_three_tries_for_the_password_and_then_raise_exception
prompt = MockPrompt.new
File.expects(:read).with(@key_file).returns(encrypted(rsa_key, "password"))
- prompt.expects(:_ask).times(3).with("Enter passphrase for #{@key_file}:", has_entries(type: 'private_key', filename: @key_file), false).returns("passwod","passphrase","passwd")
+ prompt.expects(:_ask).times(3).with("Enter passphrase for #{@key_file}:", has_entries(type: 'private_key', filename: @key_file), false).returns("passwod", "passphrase", "passwd")
if OpenSSL::PKey.respond_to?(:read)
error_class = [ArgumentError, OpenSSL::PKey::PKeyError]
else
@@ -277,7 +277,7 @@ class TestKeyFactory < NetSSHTest
end
def public(key, args = nil)
- result = ""
+ result = String.new
if !args.nil?
result << "#{args} "
end
diff --git a/test/test_known_hosts.rb b/test/test_known_hosts.rb
index 6b1fda6..f960351 100644
--- a/test/test_known_hosts.rb
+++ b/test/test_known_hosts.rb
@@ -1,4 +1,4 @@
-require 'common'
+require_relative './common'
class TestKnownHosts < NetSSHTest
def perform_test(source)
@@ -28,101 +28,123 @@ class TestKnownHosts < NetSSHTest
assert_equal(0, keys.count)
assert_equal([], keys.to_a)
- kh.add('github2.com',rsa_key)
+ kh.add('github2.com', rsa_key)
keys2 = kh.keys_for("github2.com")
assert_equal([rsa_key.to_blob], keys2.to_a.map(&:to_blob))
end
end
def test_search_for
- options = { user_known_hosts_file: path("known_hosts/github") }
- keys = Net::SSH::KnownHosts.search_for('github.com',options)
+ options = { user_known_hosts_file: path("known_hosts/github"), global_known_hosts_file: [] }
+ keys = Net::SSH::KnownHosts.search_for('github.com', options)
assert_equal(["ssh-rsa"], keys.map(&:ssh_type))
end
def test_search_for_with_hostname_and_right_ip_with_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: true }
- keys = Net::SSH::KnownHosts.search_for('gitlab.com,35.231.145.151',options)
+ keys = Net::SSH::KnownHosts.search_for('gitlab.com,35.231.145.151', options)
assert_equal(1, keys.count)
end
def test_search_for_with_hostname_and_right_ip_without_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: false }
- keys = Net::SSH::KnownHosts.search_for('gitlab.com,35.231.145.151',options)
+ keys = Net::SSH::KnownHosts.search_for('gitlab.com,35.231.145.151', options)
assert_equal(1, keys.count)
end
def test_search_for_with_hostname_and_wrong_ip_with_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: true }
- keys = Net::SSH::KnownHosts.search_for('gitlab.com,192.0.2.1',options)
+ keys = Net::SSH::KnownHosts.search_for('gitlab.com,192.0.2.1', options)
assert_equal(0, keys.count)
end
def test_search_for_with_hostname_and_wrong_ip_without_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: false }
- keys = Net::SSH::KnownHosts.search_for('gitlab.com,192.0.2.2',options)
+ keys = Net::SSH::KnownHosts.search_for('gitlab.com,192.0.2.2', options)
assert_equal(1, keys.count)
end
def test_search_for_with_hostname_only_with_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: true }
- keys = Net::SSH::KnownHosts.search_for('gitlab.com',options)
+ keys = Net::SSH::KnownHosts.search_for('gitlab.com', options)
assert_equal(1, keys.count)
end
def test_search_for_with_hostname_only_without_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: false }
- keys = Net::SSH::KnownHosts.search_for('gitlab.com',options)
+ keys = Net::SSH::KnownHosts.search_for('gitlab.com', options)
assert_equal(1, keys.count)
end
def test_search_for_with_ip_only_with_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: true }
- keys = Net::SSH::KnownHosts.search_for('35.231.145.151',options)
+ keys = Net::SSH::KnownHosts.search_for('35.231.145.151', options)
assert_equal(1, keys.count)
end
def test_search_for_with_ip_only_without_check_host_ip
options = { user_known_hosts_file: path("known_hosts/gitlab"), check_host_ip: false }
- keys = Net::SSH::KnownHosts.search_for('35.231.145.151',options)
+ keys = Net::SSH::KnownHosts.search_for('35.231.145.151', options)
assert_equal(1, keys.count)
end
def test_search_for_with_hostname_matching_pattern
options = { user_known_hosts_file: path("known_hosts/misc") }
- keys = Net::SSH::KnownHosts.search_for('subdomain.gitfoo.com',options)
+ keys = Net::SSH::KnownHosts.search_for('subdomain.gitfoo.com', options)
assert_equal(1, keys.count)
end
def test_search_for_with_hostname_not_matching_pattern_1
options = { user_known_hosts_file: path("known_hosts/misc") }
- keys = Net::SSH::KnownHosts.search_for('gitfoo.com',options)
+ keys = Net::SSH::KnownHosts.search_for('gitfoo.com', options)
assert_equal(0, keys.count)
end
def test_search_for_with_hostname_not_matching_pattern_2
options = { user_known_hosts_file: path("known_hosts/misc") }
- keys = Net::SSH::KnownHosts.search_for('subdomain.gitmisc.com',options)
+ keys = Net::SSH::KnownHosts.search_for('subdomain.gitmisc.com', options)
assert_equal(0, keys.count)
end
def test_search_for_with_hostname_not_matching_pattern_3
options = { user_known_hosts_file: path("known_hosts/misc") }
- keys = Net::SSH::KnownHosts.search_for('subsubdomain.subdomain.gitfoo.com',options)
- assert_equal(0, keys.count)
+ keys = Net::SSH::KnownHosts.search_for('subsubdomain.subdomain.gitfoo.com', options)
+ assert_equal(1, keys.count)
+ end
+
+ def test_asterisk_matches_multiple_dots
+ with_config_file(lines: ["*.git???.com #{sample_key}"]) do |path|
+ options = { user_known_hosts_file: path }
+ keys = Net::SSH::KnownHosts.search_for('subsubdomain.subdomain.gitfoo.com', options)
+ assert_equal(1, keys.count)
+
+ keys = Net::SSH::KnownHosts.search_for('subsubdomain.subdomain.gitfoo2.com', options)
+ assert_equal(0, keys.count)
+ end
+ end
+
+ def test_asterisk_matches_everything
+ with_config_file(lines: ["* #{sample_key}"]) do |path|
+ options = { user_known_hosts_file: path }
+ keys = Net::SSH::KnownHosts.search_for('subsubdomain.subdomain.gitfoo.com', options)
+ assert_equal(1, keys.count)
+
+ keys = Net::SSH::KnownHosts.search_for('subsubdomain.subdomain.gitfoo2.com', options)
+ assert_equal(1, keys.count)
+ end
end
def test_search_for_then_add
Tempfile.open('github') do |f|
f.write(File.read(path("known_hosts/github")))
options = { user_known_hosts_file: f.path }
- keys = Net::SSH::KnownHosts.search_for('github2.com',options)
+ keys = Net::SSH::KnownHosts.search_for('github2.com', options)
assert_equal(0, keys.count)
keys.add_host_key(rsa_key)
assert_equal([rsa_key.to_blob], keys.map(&:to_blob))
- keys = Net::SSH::KnownHosts.search_for('github2.com',options)
+ keys = Net::SSH::KnownHosts.search_for('github2.com', options)
assert_equal([rsa_key.to_blob], keys.map(&:to_blob))
end
end
@@ -131,6 +153,18 @@ class TestKnownHosts < NetSSHTest
File.join(File.dirname(__FILE__), relative_path)
end
+ def sample_key
+ "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=="
+ end
+
+ def with_config_file(lines: [], &block)
+ Tempfile.open('known_hosts') do |f|
+ f.write(lines.join("\n"))
+ f.close
+ yield(f.path)
+ end
+ end
+
def rsa_key
key = OpenSSL::PKey::RSA.new
if key.respond_to?(:set_key)
diff --git a/test/transport/hmac/test_md5.rb b/test/transport/hmac/test_md5.rb
index e0abccc..3188b04 100644
--- a/test/transport/hmac/test_md5.rb
+++ b/test/transport/hmac/test_md5.rb
@@ -3,41 +3,39 @@
require 'common'
require 'net/ssh/transport/hmac/md5'
-module Transport
+module Transport
module HMAC
-
class TestMD5 < NetSSHTest
def test_expected_digest_class
assert_equal OpenSSL::Digest::MD5, subject.digest_class
assert_equal OpenSSL::Digest::MD5, subject.new.digest_class
end
-
+
def test_expected_key_length
assert_equal 16, subject.key_length
assert_equal 16, subject.new.key_length
end
-
+
def test_expected_mac_length
assert_equal 16, subject.mac_length
assert_equal 16, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "\275\345\006\307y~Oi\035<.\341\031\250<\257", hmac.digest("hello world")
end
-
+
def test_key_should_be_truncated_to_required_length
hmac = subject.new("12345678901234567890")
assert_equal "1234567890123456", hmac.key
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::MD5
end
end
-
end
-end \ No newline at end of file
+end
diff --git a/test/transport/hmac/test_md5_96.rb b/test/transport/hmac/test_md5_96.rb
index 4ee1680..2b238e5 100644
--- a/test/transport/hmac/test_md5_96.rb
+++ b/test/transport/hmac/test_md5_96.rb
@@ -4,26 +4,24 @@ require 'common'
require 'transport/hmac/test_md5'
require 'net/ssh/transport/hmac/md5_96'
-module Transport
+module Transport
module HMAC
-
class TestMD5_96 < TestMD5
def test_expected_mac_length
assert_equal 12, subject.mac_length
assert_equal 12, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "\275\345\006\307y~Oi\035<.\341", hmac.digest("hello world")
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::MD5_96
end
end
-
end
-end \ No newline at end of file
+end
diff --git a/test/transport/hmac/test_none.rb b/test/transport/hmac/test_none.rb
index ae8fe7e..812075e 100644
--- a/test/transport/hmac/test_none.rb
+++ b/test/transport/hmac/test_none.rb
@@ -1,36 +1,34 @@
require 'common'
require 'net/ssh/transport/hmac/none'
-module Transport
+module Transport
module HMAC
-
class TestNone < NetSSHTest
def test_expected_digest_class
assert_nil subject.digest_class
assert_nil subject.new.digest_class
end
-
+
def test_expected_key_length
assert_equal 0, subject.key_length
assert_equal 0, subject.new.key_length
end
-
+
def test_expected_mac_length
assert_equal 0, subject.mac_length
assert_equal 0, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "", hmac.digest("hello world")
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::None
end
end
-
end
end
diff --git a/test/transport/hmac/test_ripemd160.rb b/test/transport/hmac/test_ripemd160.rb
index bcc14f8..e082485 100644
--- a/test/transport/hmac/test_ripemd160.rb
+++ b/test/transport/hmac/test_ripemd160.rb
@@ -3,36 +3,34 @@
require 'common'
require 'net/ssh/transport/hmac/ripemd160'
-module Transport
+module Transport
module HMAC
-
class TestRipemd160 < NetSSHTest
def test_expected_digest_class
assert_equal OpenSSL::Digest::RIPEMD160, subject.digest_class
assert_equal OpenSSL::Digest::RIPEMD160, subject.new.digest_class
end
-
+
def test_expected_key_length
assert_equal 20, subject.key_length
assert_equal 20, subject.new.key_length
end
-
+
def test_expected_mac_length
assert_equal 20, subject.mac_length
assert_equal 20, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "\xE4\x10\t\xB3\xD8,\x14\xA0k\x10\xB5\x0F?\x0E\x96q\x02\x16;E", hmac.digest("hello world")
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::RIPEMD160
end
end
-
end
end
diff --git a/test/transport/hmac/test_sha1.rb b/test/transport/hmac/test_sha1.rb
index be64bf6..4bf3b28 100644
--- a/test/transport/hmac/test_sha1.rb
+++ b/test/transport/hmac/test_sha1.rb
@@ -3,36 +3,34 @@
require 'common'
require 'net/ssh/transport/hmac/sha1'
-module Transport
+module Transport
module HMAC
-
class TestSHA1 < NetSSHTest
def test_expected_digest_class
assert_equal OpenSSL::Digest::SHA1, subject.digest_class
assert_equal OpenSSL::Digest::SHA1, subject.new.digest_class
end
-
+
def test_expected_key_length
assert_equal 20, subject.key_length
assert_equal 20, subject.new.key_length
end
-
+
def test_expected_mac_length
assert_equal 20, subject.mac_length
assert_equal 20, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "\000\004W\202\204+&\335\311\251P\266\250\214\276\206;\022U\365", hmac.digest("hello world")
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::SHA1
end
end
-
end
-end \ No newline at end of file
+end
diff --git a/test/transport/hmac/test_sha1_96.rb b/test/transport/hmac/test_sha1_96.rb
index d5dec22..cefc16f 100644
--- a/test/transport/hmac/test_sha1_96.rb
+++ b/test/transport/hmac/test_sha1_96.rb
@@ -4,26 +4,24 @@ require 'common'
require 'transport/hmac/test_sha1'
require 'net/ssh/transport/hmac/sha1_96'
-module Transport
+module Transport
module HMAC
-
class TestSHA1_96 < TestSHA1
def test_expected_mac_length
assert_equal 12, subject.mac_length
assert_equal 12, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "\000\004W\202\204+&\335\311\251P\266", hmac.digest("hello world")
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::SHA1_96
end
end
-
end
-end \ No newline at end of file
+end
diff --git a/test/transport/hmac/test_sha2_256.rb b/test/transport/hmac/test_sha2_256.rb
index 8a2e07d..834967b 100644
--- a/test/transport/hmac/test_sha2_256.rb
+++ b/test/transport/hmac/test_sha2_256.rb
@@ -5,7 +5,6 @@ require 'net/ssh/transport/hmac/sha2_256'
module Transport
module HMAC
-
class TestSHA2_256 < NetSSHTest
def test_expected_digest_class
assert_equal OpenSSL::Digest::SHA256, subject.digest_class
diff --git a/test/transport/hmac/test_sha2_256_96.rb b/test/transport/hmac/test_sha2_256_96.rb
index 07799fe..4083b1a 100644
--- a/test/transport/hmac/test_sha2_256_96.rb
+++ b/test/transport/hmac/test_sha2_256_96.rb
@@ -4,26 +4,24 @@ require 'common'
require 'transport/hmac/test_sha2_256'
require 'net/ssh/transport/hmac/sha2_256_96'
-module Transport
+module Transport
module HMAC
-
class TestSHA2_256_96 < TestSHA2_256
def test_expected_mac_length
assert_equal 12, subject.mac_length
assert_equal 12, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "\x16^>\x9FhO}\xB1>(\xBAF", hmac.digest("hello world")
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::SHA2_256_96
end
end
-
end
end
diff --git a/test/transport/hmac/test_sha2_256_etm.rb b/test/transport/hmac/test_sha2_256_etm.rb
index f66afda..5a50cef 100644
--- a/test/transport/hmac/test_sha2_256_etm.rb
+++ b/test/transport/hmac/test_sha2_256_etm.rb
@@ -5,7 +5,6 @@ require 'net/ssh/transport/hmac/sha2_256_etm'
module Transport
module HMAC
-
class TestSHA2_256_Etm < NetSSHTest
def test_expected_digest_class
assert_equal OpenSSL::Digest::SHA256, subject.digest_class
diff --git a/test/transport/hmac/test_sha2_512.rb b/test/transport/hmac/test_sha2_512.rb
index 886c683..a1b7048 100644
--- a/test/transport/hmac/test_sha2_512.rb
+++ b/test/transport/hmac/test_sha2_512.rb
@@ -5,7 +5,6 @@ require 'net/ssh/transport/hmac/sha2_512'
module Transport
module HMAC
-
class TestSHA2_512 < NetSSHTest
def test_expected_digest_class
assert_equal OpenSSL::Digest::SHA512, subject.digest_class
diff --git a/test/transport/hmac/test_sha2_512_96.rb b/test/transport/hmac/test_sha2_512_96.rb
index 955da06..a80bc2c 100644
--- a/test/transport/hmac/test_sha2_512_96.rb
+++ b/test/transport/hmac/test_sha2_512_96.rb
@@ -4,26 +4,24 @@ require 'common'
require 'transport/hmac/test_sha2_512'
require 'net/ssh/transport/hmac/sha2_512_96'
-module Transport
+module Transport
module HMAC
-
class TestSHA2_512_96 < TestSHA2_512
def test_expected_mac_length
assert_equal 12, subject.mac_length
assert_equal 12, subject.new.mac_length
end
-
+
def test_expected_digest
hmac = subject.new("1234567890123456")
assert_equal "^\xB6\"\xED\x8B\xC4\xDE\xD4\xCF\xD0\r\x18", hmac.digest("hello world")
end
-
+
private
-
+
def subject
Net::SSH::Transport::HMAC::SHA2_512_96
end
end
-
end
end
diff --git a/test/transport/hmac/test_sha2_512_etm.rb b/test/transport/hmac/test_sha2_512_etm.rb
index 364905e..0805b97 100644
--- a/test/transport/hmac/test_sha2_512_etm.rb
+++ b/test/transport/hmac/test_sha2_512_etm.rb
@@ -5,7 +5,6 @@ require 'net/ssh/transport/hmac/sha2_512_etm'
module Transport
module HMAC
-
class TestSHA2_512_Etm < NetSSHTest
def test_expected_digest_class
assert_equal OpenSSL::Digest::SHA512, subject.digest_class
diff --git a/test/transport/kex/test_curve25519_sha256.rb b/test/transport/kex/test_curve25519_sha256.rb
index 8177a38..42bbe0a 100644
--- a/test/transport/kex/test_curve25519_sha256.rb
+++ b/test/transport/kex/test_curve25519_sha256.rb
@@ -13,7 +13,7 @@ unless ENV['NET_SSH_NO_ED25519']
raise 'No X25519 set NET_SSH_NO_ED25519 to ignore this test' unless Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
@ecdh = @algorithms = @connection = @server_key =
- @packet_data = @shared_secret = nil
+ @packet_data = @shared_secret = nil
end
def test_exchange_keys_should_return_expected_results_when_successful
@@ -153,4 +153,4 @@ unless ENV['NET_SSH_NO_ED25519']
end
end
end
-end \ No newline at end of file
+end
diff --git a/test/transport/kex/test_diffie_hellman_group14_sha1.rb b/test/transport/kex/test_diffie_hellman_group14_sha1.rb
index 5d006e1..9c06c0c 100644
--- a/test/transport/kex/test_diffie_hellman_group14_sha1.rb
+++ b/test/transport/kex/test_diffie_hellman_group14_sha1.rb
@@ -1,11 +1,10 @@
-require 'common'
+require_relative '../../common'
require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
-require 'transport/kex/test_diffie_hellman_group1_sha1'
+require_relative './test_diffie_hellman_group1_sha1'
require 'ostruct'
-module Transport
+module Transport
module Kex
-
class TestDiffieHellmanGroup14SHA1 < TestDiffieHellmanGroup1SHA1
def subject
Net::SSH::Transport::Kex::DiffieHellmanGroup14SHA1
diff --git a/test/transport/kex/test_diffie_hellman_group14_sha256.rb b/test/transport/kex/test_diffie_hellman_group14_sha256.rb
new file mode 100644
index 0000000..db15d5b
--- /dev/null
+++ b/test/transport/kex/test_diffie_hellman_group14_sha256.rb
@@ -0,0 +1,16 @@
+require_relative '../../common'
+require_relative './test_diffie_hellman_group14_sha1'
+
+module Transport
+ module Kex
+ class TestDiffieHellmanGroup14SHA256 < TestDiffieHellmanGroup14SHA1
+ def subject
+ Net::SSH::Transport::Kex::DiffieHellmanGroup14SHA256
+ end
+
+ def digest_type
+ OpenSSL::Digest::SHA256
+ end
+ end
+ end
+end
diff --git a/test/transport/kex/test_diffie_hellman_group1_sha1.rb b/test/transport/kex/test_diffie_hellman_group1_sha1.rb
index be51720..a3b846c 100644
--- a/test/transport/kex/test_diffie_hellman_group1_sha1.rb
+++ b/test/transport/kex/test_diffie_hellman_group1_sha1.rb
@@ -4,13 +4,12 @@ require 'ostruct'
module Transport
module Kex
-
class TestDiffieHellmanGroup1SHA1 < NetSSHTest
include Net::SSH::Transport::Constants
def setup
@dh_options = @dh = @algorithms = @connection = @server_key =
- @packet_data = @shared_secret = nil
+ @packet_data = @shared_secret = nil
end
def digest_type
@@ -86,7 +85,7 @@ module Transport
private
- def exchange!(options={})
+ def exchange!(options = {})
connection.expect do |t, buffer|
assert_equal KEXDH_INIT, buffer.type
assert_equal dh.dh.pub_key, buffer.read_bignum
@@ -100,7 +99,7 @@ module Transport
dh.exchange_keys
end
- def dh_options(options={})
+ def dh_options(options = {})
@dh_options = options
end
@@ -108,7 +107,7 @@ module Transport
@dh ||= subject.new(algorithms, connection, packet_data.merge(need_bytes: 20).merge(@dh_options || {}))
end
- def algorithms(options={})
+ def algorithms(options = {})
@algorithms ||= OpenStruct.new(host_key: options[:host_key] || "ssh-rsa", host_key_format: options[:host_key] || "ssh-rsa")
end
@@ -122,7 +121,7 @@ module Transport
# 512 bits is the smallest possible key that will work with this, so
# we use it for speed reasons
- def server_key(bits=512)
+ def server_key(bits = 512)
@server_key ||= OpenSSL::PKey::RSA.new(bits)
end
@@ -144,14 +143,14 @@ module Transport
def session_id
@session_id ||= begin
buffer = Net::SSH::Buffer.from(:string, packet_data[:client_version_string],
- :string, packet_data[:server_version_string],
- :string, packet_data[:client_algorithm_packet],
- :string, packet_data[:server_algorithm_packet],
- :string, Net::SSH::Buffer.from(:key, server_key),
- :bignum, dh.dh.pub_key,
- :bignum, server_dh_pubkey,
- :bignum, shared_secret)
- OpenSSL::Digest::SHA1.digest(buffer.to_s)
+ :string, packet_data[:server_version_string],
+ :string, packet_data[:client_algorithm_packet],
+ :string, packet_data[:server_algorithm_packet],
+ :string, Net::SSH::Buffer.from(:key, server_key),
+ :bignum, dh.dh.pub_key,
+ :bignum, server_dh_pubkey,
+ :bignum, shared_secret)
+ digest_type.digest(buffer.to_s)
end
end
@@ -159,7 +158,7 @@ module Transport
@signature ||= server_key.ssh_do_sign(session_id)
end
- def bn(number, base=10)
+ def bn(number, base = 10)
OpenSSL::BN.new(number.to_s, base)
end
@@ -167,6 +166,5 @@ module Transport
Net::SSH::Buffer.from(*args)
end
end
-
end
end
diff --git a/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb b/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb
index 800a8c6..d0df04b 100644
--- a/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb
+++ b/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb
@@ -2,61 +2,61 @@ require 'common'
require 'transport/kex/test_diffie_hellman_group1_sha1'
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
-module Transport
+module Transport
module Kex
-
class TestDiffieHellmanGroupExchangeSHA1 < TestDiffieHellmanGroup1SHA1
KEXDH_GEX_GROUP = 31
KEXDH_GEX_INIT = 32
KEXDH_GEX_REPLY = 33
KEXDH_GEX_REQUEST = 34
-
+
def test_exchange_with_fewer_than_minimum_bits_uses_minimum_bits
dh_options need_bytes: 20
assert_equal 1024, need_bits
assert_nothing_raised { exchange! }
end
-
+
def test_exchange_with_optional_minimum_bits_declared
dh_options minimum_dh_bits: 4096
assert_equal 4096, need_bits
assert_nothing_raised { exchange! }
end
-
+
def test_exchange_with_fewer_than_maximum_bits_uses_need_bits
dh_options need_bytes: 500
need_bits(8001)
assert_nothing_raised { exchange! }
end
-
+
def test_exchange_with_more_than_maximum_bits_uses_maximum_bits
dh_options need_bytes: 2000
need_bits(8192)
assert_nothing_raised { exchange! }
end
-
+
def test_that_p_and_g_are_provided_by_the_server
assert_nothing_raised { exchange! p: default_p + 2, g: 3 }
assert_equal default_p + 2, dh.dh.p
assert_equal 3, dh.dh.g
end
-
+
private
-
- def need_bits(bits=1024)
+
+ def need_bits(bits = 1024)
@need_bits ||= need_minimum(bits)
end
-
- def need_minimum(bits=1024)
+
+ def need_minimum(bits = 1024)
return @dh_options[:minimum_dh_bits] if @dh_options && @dh_options[:minimum_dh_bits]
+
bits
end
-
+
def default_p
142326151570335518660743995281621698377057354949884468943021767573608899048361360422513557553514790045512299468953431585300812548859419857171094366358158903433167915517332113861059747425408670144201099811846875730766487278261498262568348338476437200556998366087779709990807518291581860338635288400119315130179
end
-
- def exchange!(options={})
+
+ def exchange!(options = {})
connection.expect do |t, buffer|
assert_equal KEXDH_GEX_REQUEST, buffer.type
assert_equal need_minimum, buffer.read_long
@@ -73,37 +73,36 @@ module Transport
end
end
end
-
+
dh.exchange_keys
end
-
+
def subject
Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA1
end
-
+
def digest_type
OpenSSL::Digest::SHA1
end
-
+
def session_id
@session_id ||= begin
buffer = Net::SSH::Buffer.from(:string, packet_data[:client_version_string],
- :string, packet_data[:server_version_string],
- :string, packet_data[:client_algorithm_packet],
- :string, packet_data[:server_algorithm_packet],
- :string, Net::SSH::Buffer.from(:key, server_key),
- :long, 1024,
- :long, need_bits, # need bits, figure this part out,
- :long, 8192,
- :bignum, dh.dh.p,
- :bignum, dh.dh.g,
- :bignum, dh.dh.pub_key,
- :bignum, server_dh_pubkey,
- :bignum, shared_secret)
+ :string, packet_data[:server_version_string],
+ :string, packet_data[:client_algorithm_packet],
+ :string, packet_data[:server_algorithm_packet],
+ :string, Net::SSH::Buffer.from(:key, server_key),
+ :long, 1024,
+ :long, need_bits, # need bits, figure this part out,
+ :long, 8192,
+ :bignum, dh.dh.p,
+ :bignum, dh.dh.g,
+ :bignum, dh.dh.pub_key,
+ :bignum, server_dh_pubkey,
+ :bignum, shared_secret)
digest_type.digest(buffer.to_s)
end
end
end
-
end
end
diff --git a/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb b/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb
index 6355c18..d3d6d76 100644
--- a/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb
+++ b/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb
@@ -2,20 +2,18 @@ require 'common'
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
require 'transport/kex/test_diffie_hellman_group_exchange_sha1'
-module Transport
+module Transport
module Kex
-
class TestDiffieHellmanGroupExchangeSHA256 < TestDiffieHellmanGroupExchangeSHA1
private
-
+
def subject
Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA256
end
-
+
def digest_type
OpenSSL::Digest::SHA256
end
end
-
end
end
diff --git a/test/transport/kex/test_ecdh_sha2_nistp256.rb b/test/transport/kex/test_ecdh_sha2_nistp256.rb
index 932d8d7..9f26428 100644
--- a/test/transport/kex/test_ecdh_sha2_nistp256.rb
+++ b/test/transport/kex/test_ecdh_sha2_nistp256.rb
@@ -1,7 +1,7 @@
require 'openssl'
require 'ostruct'
require_relative '../../common'
-require 'transport/kex/test_diffie_hellman_group1_sha1'
+require_relative './test_diffie_hellman_group1_sha1'
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
module Transport
@@ -11,7 +11,7 @@ module Transport
def setup
@ecdh = @algorithms = @connection = @server_key =
- @packet_data = @shared_secret = nil
+ @packet_data = @shared_secret = nil
end
def test_exchange_keys_should_return_expected_results_when_successful
diff --git a/test/transport/kex/test_ecdh_sha2_nistp384.rb b/test/transport/kex/test_ecdh_sha2_nistp384.rb
index 395f42f..fc722df 100644
--- a/test/transport/kex/test_ecdh_sha2_nistp384.rb
+++ b/test/transport/kex/test_ecdh_sha2_nistp384.rb
@@ -6,7 +6,7 @@ module Transport
class TestEcdhSHA2NistP384 < TestEcdhSHA2NistP256
def setup
@ecdh = @algorithms = @connection = @server_key =
- @packet_data = @shared_secret = nil
+ @packet_data = @shared_secret = nil
end
def test_exchange_keys_should_return_expected_results_when_successful
diff --git a/test/transport/kex/test_ecdh_sha2_nistp521.rb b/test/transport/kex/test_ecdh_sha2_nistp521.rb
index 42ef32f..fc7543e 100644
--- a/test/transport/kex/test_ecdh_sha2_nistp521.rb
+++ b/test/transport/kex/test_ecdh_sha2_nistp521.rb
@@ -6,7 +6,7 @@ module Transport
class TestEcdhSHA2NistP521 < TestEcdhSHA2NistP256
def setup
@ecdh = @algorithms = @connection = @server_key =
- @packet_data = @shared_secret = nil
+ @packet_data = @shared_secret = nil
end
def test_exchange_keys_should_return_expected_results_when_successful
diff --git a/test/transport/test_algorithms.rb b/test/transport/test_algorithms.rb
index 105f3af..e52782c 100644
--- a/test/transport/test_algorithms.rb
+++ b/test/transport/test_algorithms.rb
@@ -3,7 +3,6 @@ require 'logger'
require 'net/ssh/transport/algorithms'
module Transport
-
class TestAlgorithms < NetSSHTest
include Net::SSH::Transport::Constants
@@ -18,8 +17,8 @@ module Transport
end
def test_constructor_should_build_default_list_of_preferred_algorithms
- assert_equal ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa], algorithms[:host_key]
- assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha1], algorithms[:kex]
+ assert_equal ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512], algorithms[:host_key]
+ assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1], algorithms[:kex]
assert_equal %w[aes256-ctr aes192-ctr aes128-ctr], algorithms[:encryption]
assert_equal %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com hmac-sha2-512 hmac-sha2-256 hmac-sha1], algorithms[:hmac]
assert_equal %w[none zlib@openssh.com zlib], algorithms[:compression]
@@ -27,8 +26,8 @@ module Transport
end
def test_constructor_should_build_complete_list_of_algorithms_with_append_all_supported_algorithms
- assert_equal ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa ssh-dss], algorithms(append_all_supported_algorithms: true)[:host_key]
- assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1 diffie-hellman-group1-sha1], algorithms(append_all_supported_algorithms: true)[:kex]
+ assert_equal ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512 ssh-dss], algorithms(append_all_supported_algorithms: true)[:host_key]
+ assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1 diffie-hellman-group1-sha1], algorithms(append_all_supported_algorithms: true)[:kex]
assert_equal %w[aes256-ctr aes192-ctr aes128-ctr aes256-cbc aes192-cbc aes128-cbc rijndael-cbc@lysator.liu.se blowfish-ctr blowfish-cbc cast128-ctr cast128-cbc 3des-ctr 3des-cbc idea-cbc none], algorithms(append_all_supported_algorithms: true)[:encryption]
assert_equal %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com hmac-sha2-512 hmac-sha2-256 hmac-sha1 hmac-sha2-512-96 hmac-sha2-256-96 hmac-sha1-96 hmac-ripemd160 hmac-ripemd160@openssh.com hmac-md5 hmac-md5-96 none], algorithms(append_all_supported_algorithms: true)[:hmac]
assert_equal %w[none zlib@openssh.com zlib], algorithms(append_all_supported_algorithms: true)[:compression]
@@ -43,12 +42,15 @@ module Transport
end
def test_constructor_with_preferred_host_key_type_should_put_preferred_host_key_type_first
- assert_equal %w[ssh-dss] + ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa], algorithms(host_key: "ssh-dss", append_all_supported_algorithms: true)[:host_key]
+ assert_equal %w[ssh-dss] + ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512], algorithms(host_key: "ssh-dss", append_all_supported_algorithms: true)[:host_key]
end
def test_constructor_with_known_hosts_reporting_known_host_key_should_use_that_host_key_type
- Net::SSH::KnownHosts.expects(:search_for).with("net.ssh.test,127.0.0.1", {}).returns([stub("key", ssh_type: "ssh-dss")])
- assert_equal %w[ssh-dss] + ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa], algorithms[:host_key]
+ Net::SSH::KnownHosts.expects(:search_for).with(
+ "net.ssh.test,127.0.0.1",
+ { user_known_hosts_file: "/dev/null", global_known_hosts_file: "/dev/null" }
+ ).returns([stub("key", ssh_type: "ssh-dss")])
+ assert_equal %w[ssh-dss] + ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512], algorithms[:host_key]
end
def ed_host_keys
@@ -73,7 +75,7 @@ module Transport
end
def test_constructor_with_unrecognized_host_key_type_should_return_whats_supported
- assert_equal ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa ssh-dss],
+ assert_equal ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512 ssh-dss],
algorithms(host_key: "bogus ssh-rsa", append_all_supported_algorithms: true)[:host_key]
end
@@ -90,22 +92,22 @@ module Transport
end
def test_constructor_with_preferred_kex_should_put_preferred_kex_first
- assert_equal %w[diffie-hellman-group1-sha1] + x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1],
+ assert_equal %w[diffie-hellman-group1-sha1] + x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1],
algorithms(kex: "diffie-hellman-group1-sha1", append_all_supported_algorithms: true)[:kex]
end
def test_constructor_with_unrecognized_kex_should_not_raise_exception
- assert_equal %w[diffie-hellman-group1-sha1] + x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1],
+ assert_equal %w[diffie-hellman-group1-sha1] + x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1],
algorithms(kex: %w[bogus diffie-hellman-group1-sha1], append_all_supported_algorithms: true)[:kex]
end
def test_constructor_with_preferred_kex_supports_additions
- assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1 diffie-hellman-group1-sha1],
+ assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1 diffie-hellman-group1-sha1],
algorithms(kex: %w[+diffie-hellman-group1-sha1])[:kex]
end
def test_constructor_with_preferred_kex_supports_removals_with_wildcard
- assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256],
+ assert_equal x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha256],
algorithms(kex: %w[-diffie-hellman-group*-sha1 -diffie-hellman-group-exchange-sha1])[:kex]
end
@@ -144,7 +146,7 @@ module Transport
def test_constructor_with_unrecognized_hmac_should_ignore_those
assert_equal %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com hmac-sha2-512 hmac-sha2-256 hmac-sha1 hmac-sha2-512-96 hmac-sha2-256-96 hmac-sha1-96 hmac-ripemd160 hmac-ripemd160@openssh.com hmac-md5 hmac-md5-96 none],
- algorithms(hmac: "unknown hmac-md5-96", append_all_supported_algorithms: true)[:hmac]
+ algorithms(hmac: "unknown hmac-md5-96", append_all_supported_algorithms: true)[:hmac]
end
def test_constructor_with_preferred_hmac_supports_additions
@@ -182,7 +184,7 @@ module Transport
end
def test_constructor_with_host_key_removals_with_wildcard
- assert_equal ed_host_keys + %w[ecdsa-sha2-nistp521-cert-v01@openssh.com ecdsa-sha2-nistp384-cert-v01@openssh.com ecdsa-sha2-nistp256-cert-v01@openssh.com ecdsa-sha2-nistp521 ecdsa-sha2-nistp384 ecdsa-sha2-nistp256], algorithms(host_key: %w[-ssh-rsa* -ssh-dss])[:host_key]
+ assert_equal ed_host_keys + %w[ecdsa-sha2-nistp521-cert-v01@openssh.com ecdsa-sha2-nistp384-cert-v01@openssh.com ecdsa-sha2-nistp256-cert-v01@openssh.com ecdsa-sha2-nistp521 ecdsa-sha2-nistp384 ecdsa-sha2-nistp256], algorithms(host_key: %w[-ssh-rsa* -ssh-dss -rsa-sha*])[:host_key]
end
def test_initial_state_should_be_neither_pending_nor_initialized
@@ -191,7 +193,7 @@ module Transport
end
def test_key_exchange_when_initiated_by_server
- transport.expect do |t, buffer|
+ transport.expect do |_t, buffer|
assert_kexinit(buffer)
install_mock_key_exchange(buffer)
end
@@ -204,7 +206,7 @@ module Transport
def test_key_exchange_when_initiated_by_client
state = nil
- transport.expect do |t, buffer|
+ transport.expect do |_t, buffer|
assert_kexinit(buffer)
state = :sent_kexinit
install_mock_key_exchange(buffer)
@@ -222,7 +224,7 @@ module Transport
def test_key_exchange_when_server_does_not_support_preferred_kex_should_fallback_to_secondary
kexinit kex: "diffie-hellman-group14-sha1"
- transport.expect do |t,buffer|
+ transport.expect do |_t, buffer|
assert_kexinit(buffer)
install_mock_key_exchange(buffer, kex: Net::SSH::Transport::Kex::DiffieHellmanGroup1SHA1)
end
@@ -231,7 +233,7 @@ module Transport
def test_key_exchange_when_server_does_not_support_any_preferred_kex_should_raise_error
kexinit kex: "something-obscure"
- transport.expect { |t,buffer| assert_kexinit(buffer) }
+ transport.expect { |_t, buffer| assert_kexinit(buffer) }
assert_raises(Net::SSH::Exception) { algorithms.accept_kexinit(kexinit) }
end
@@ -259,7 +261,7 @@ module Transport
def test_exchange_with_zlib_compression_enabled_sets_compression_to_standard
algorithms compression: 'zlib'
- transport.expect do |t, buffer|
+ transport.expect do |_t, buffer|
assert_kexinit(buffer, compression_client: 'zlib', compression_server: 'zlib')
install_mock_key_exchange(buffer)
end
@@ -274,7 +276,7 @@ module Transport
def test_exchange_with_zlib_at_openssh_dot_com_compression_enabled_sets_compression_to_delayed
algorithms compression: 'zlib@openssh.com'
- transport.expect do |t, buffer|
+ transport.expect do |_t, buffer|
assert_kexinit(buffer, compression_client: 'zlib@openssh.com', compression_server: 'zlib@openssh.com')
install_mock_key_exchange(buffer)
end
@@ -289,7 +291,7 @@ module Transport
# Verification for https://github.com/net-ssh/net-ssh/issues/483
def test_that_algorithm_undefined_doesnt_throw_exception
# Create a logger explicitly with DEBUG logging
- string_io = StringIO.new("")
+ string_io = StringIO.new(String.new)
debug_logger = Logger.new(string_io)
debug_logger.level = Logger::DEBUG
@@ -333,27 +335,28 @@ module Transport
private
- def install_mock_key_exchange(buffer, options={})
+ def install_mock_key_exchange(buffer, options = {})
kex = options[:kex] || Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA256
- Net::SSH::Transport::Kex::MAP.each do |name, klass|
+ Net::SSH::Transport::Kex::MAP.each do |_name, klass|
next if klass == kex
+
klass.expects(:new).never
end
kex.expects(:new)
.with(algorithms, transport,
- client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
- server_version_string: transport.server_version.version,
- server_algorithm_packet: kexinit.to_s,
- client_algorithm_packet: buffer.to_s,
- need_bytes: 32,
- minimum_dh_bits: nil,
- logger: nil)
+ client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
+ server_version_string: transport.server_version.version,
+ server_algorithm_packet: kexinit.to_s,
+ client_algorithm_packet: buffer.to_s,
+ need_bytes: 32,
+ minimum_dh_bits: nil,
+ logger: nil)
.returns(stub("kex", exchange_keys: { shared_secret: shared_secret, session_id: session_id, hashing_algorithm: hashing_algorithm }))
end
- def install_mock_algorithm_lookups(options={})
+ def install_mock_algorithm_lookups(options = {})
params = { shared: shared_secret.to_ssh, hash: session_id, digester: hashing_algorithm }
Net::SSH::Transport::CipherFactory.expects(:get)
.with(options[:client_cipher] || "aes256-ctr", params.merge(iv: key("A"), key: key("C"), encrypt: true))
@@ -383,31 +386,31 @@ module Transport
hashing_algorithm.digest(shared_secret.to_ssh + session_id + salt + session_id)
end
- def cipher(type, options={})
+ def cipher(type, options = {})
Net::SSH::Transport::CipherFactory.get(type, options)
end
- def kexinit(options={})
+ def kexinit(options = {})
@kexinit ||= P(:byte, KEXINIT,
- :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF),
- :string, options[:kex] || "diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1",
- :string, options[:host_key] || "ssh-rsa,ssh-dss",
- :string, options[:encryption_client] || "aes256-ctr,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc",
- :string, options[:encryption_server] || "aes256-ctr,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc",
- :string, options[:hmac_client] || "hmac-sha2-256,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96",
- :string, options[:hmac_server] || "hmac-sha2-256,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96",
- :string, options[:compression_client] || "none,zlib@openssh.com,zlib",
- :string, options[:compression_server] || "none,zlib@openssh.com,zlib",
- :string, options[:language_client] || "",
- :string, options[:language_server] || "",
- :bool, options[:first_kex_follows])
- end
-
- def assert_kexinit(buffer, options={})
+ :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF), :long, rand(0xFFFFFFFF),
+ :string, options[:kex] || "diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1",
+ :string, options[:host_key] || "ssh-rsa,ssh-dss",
+ :string, options[:encryption_client] || "aes256-ctr,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc",
+ :string, options[:encryption_server] || "aes256-ctr,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,idea-cbc",
+ :string, options[:hmac_client] || "hmac-sha2-256,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96",
+ :string, options[:hmac_server] || "hmac-sha2-256,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96",
+ :string, options[:compression_client] || "none,zlib@openssh.com,zlib",
+ :string, options[:compression_server] || "none,zlib@openssh.com,zlib",
+ :string, options[:language_client] || "",
+ :string, options[:language_server] || "",
+ :bool, options[:first_kex_follows])
+ end
+
+ def assert_kexinit(buffer, options = {})
assert_equal KEXINIT, buffer.type
assert_equal 16, buffer.read(16).length
- assert_equal options[:kex] || (x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha1]).join(','), buffer.read_string
- assert_equal options[:host_key] || (ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa]).join(','), buffer.read_string
+ assert_equal options[:kex] || (x25519_kex + ec_kex + %w[diffie-hellman-group-exchange-sha256 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1]).join(','), buffer.read_string
+ assert_equal options[:host_key] || (ed_ec_host_keys + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512]).join(','), buffer.read_string
assert_equal options[:encryption_client] || 'aes256-ctr,aes192-ctr,aes128-ctr', buffer.read_string
assert_equal options[:encryption_server] || 'aes256-ctr,aes192-ctr,aes128-ctr', buffer.read_string
assert_equal options[:hmac_client] || 'hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-sha1', buffer.read_string
@@ -430,16 +433,20 @@ module Transport
assert_equal :server_hmac, transport.server_options[:hmac]
end
- def algorithms(algorithms_options={}, transport_options={})
+ def algorithms(algorithms_options = {}, transport_options = {})
@algorithms ||= Net::SSH::Transport::Algorithms.new(
transport(transport_options),
algorithms_options
)
end
- def transport(transport_options={})
- @transport ||= MockTransport.new(transport_options)
+ def transport(transport_options = {})
+ @transport ||= MockTransport.new(
+ {
+ user_known_hosts_file: '/dev/null',
+ global_known_hosts_file: '/dev/null'
+ }.merge(transport_options)
+ )
end
end
-
end
diff --git a/test/transport/test_cipher_factory.rb b/test/transport/test_cipher_factory.rb
index 49ff2cd..0d651aa 100644
--- a/test/transport/test_cipher_factory.rb
+++ b/test/transport/test_cipher_factory.rb
@@ -4,73 +4,72 @@ require 'common'
require 'net/ssh/transport/cipher_factory'
module Transport
-
class TestCipherFactory < NetSSHTest
def self.if_supported?(name)
yield if Net::SSH::Transport::CipherFactory.supported?(name)
end
def test_lengths_for_none
- assert_equal [0,0], factory.get_lengths("none")
- assert_equal [0,0], factory.get_lengths("bogus")
+ assert_equal [0, 0], factory.get_lengths("none")
+ assert_equal [0, 0], factory.get_lengths("bogus")
end
def test_lengths_for_blowfish_cbc
- assert_equal [16,8], factory.get_lengths("blowfish-cbc")
+ assert_equal [16, 8], factory.get_lengths("blowfish-cbc")
end
if_supported?("idea-cbc") do
def test_lengths_for_idea_cbc
- assert_equal [16,8], factory.get_lengths("idea-cbc")
+ assert_equal [16, 8], factory.get_lengths("idea-cbc")
end
end
def test_lengths_for_rijndael_cbc
- assert_equal [32,16], factory.get_lengths("rijndael-cbc@lysator.liu.se")
+ assert_equal [32, 16], factory.get_lengths("rijndael-cbc@lysator.liu.se")
end
def test_lengths_for_cast128_cbc
- assert_equal [16,8], factory.get_lengths("cast128-cbc")
+ assert_equal [16, 8], factory.get_lengths("cast128-cbc")
end
def test_lengths_for_3des_cbc
- assert_equal [24,8], factory.get_lengths("3des-cbc")
+ assert_equal [24, 8], factory.get_lengths("3des-cbc")
end
def test_lengths_for_aes128_cbc
- assert_equal [16,16], factory.get_lengths("aes128-cbc")
+ assert_equal [16, 16], factory.get_lengths("aes128-cbc")
end
def test_lengths_for_aes192_cbc
- assert_equal [24,16], factory.get_lengths("aes192-cbc")
+ assert_equal [24, 16], factory.get_lengths("aes192-cbc")
end
def test_lengths_for_aes256_cbc
- assert_equal [32,16], factory.get_lengths("aes256-cbc")
+ assert_equal [32, 16], factory.get_lengths("aes256-cbc")
end
def test_lengths_for_3des_ctr
- assert_equal [24,8], factory.get_lengths("3des-ctr")
+ assert_equal [24, 8], factory.get_lengths("3des-ctr")
end
def test_lengths_for_aes128_ctr
- assert_equal [16,16], factory.get_lengths("aes128-ctr")
+ assert_equal [16, 16], factory.get_lengths("aes128-ctr")
end
def test_lengths_for_aes192_ctr
- assert_equal [24,16], factory.get_lengths("aes192-ctr")
+ assert_equal [24, 16], factory.get_lengths("aes192-ctr")
end
def test_lengths_for_aes256_ctr
- assert_equal [32,16], factory.get_lengths("aes256-ctr")
+ assert_equal [32, 16], factory.get_lengths("aes256-ctr")
end
def test_lengths_for_blowfish_ctr
- assert_equal [16,8], factory.get_lengths("blowfish-ctr")
+ assert_equal [16, 8], factory.get_lengths("blowfish-ctr")
end
def test_lengths_for_cast128_ctr
- assert_equal [16,8], factory.get_lengths("cast128-ctr")
+ assert_equal [16, 8], factory.get_lengths("cast128-ctr")
end
BLOWFISH_CBC = "\210\021\200\315\240_\026$\352\204g\233\244\242x\332e\370\001\327\224Nv@9_\323\037\252kb\037\036\237\375]\343/y\037\237\312Q\f7]\347Y\005\275%\377\0010$G\272\250B\265Nd\375\342\372\025r6}+Y\213y\n\237\267\\\374^\346BdJ$\353\220Ik\023<\236&H\277=\225"
@@ -232,7 +231,7 @@ module Transport
end
def test_aes256_ctr_for_encryption2
- assert_equal [AES256_CTR,AES256_CTR2], encrypt2("aes256-ctr")
+ assert_equal [AES256_CTR, AES256_CTR2], encrypt2("aes256-ctr")
end
def test_aes256_ctr_for_decryption
@@ -308,5 +307,4 @@ module Transport
[first, second]
end
end
-
end
diff --git a/test/transport/test_hmac.rb b/test/transport/test_hmac.rb
index 4e2238b..4317b1a 100644
--- a/test/transport/test_hmac.rb
+++ b/test/transport/test_hmac.rb
@@ -2,12 +2,11 @@ require 'common'
require 'net/ssh/transport/hmac'
module Transport
-
class TestHMAC < NetSSHTest
- Net::SSH::Transport::HMAC::MAP.each do |name, value|
+ Net::SSH::Transport::HMAC::MAP.each do |name, _value|
method = name.tr("-", "_")
define_method("test_get_with_#{method}_returns_new_hmac_instance") do
- key = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!&$%"[0,Net::SSH::Transport::HMAC::MAP[name].key_length]
+ key = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!&$%"[0, Net::SSH::Transport::HMAC::MAP[name].key_length]
hmac = Net::SSH::Transport::HMAC.get(name, key, { shared: "123", hash: "^&*", digester: OpenSSL::Digest::SHA1 })
assert_instance_of Net::SSH::Transport::HMAC::MAP[name], hmac
assert_equal key, hmac.key
@@ -30,5 +29,4 @@ module Transport
end
end
end
-
end
diff --git a/test/transport/test_identity_cipher.rb b/test/transport/test_identity_cipher.rb
index a8f87d6..3f332db 100644
--- a/test/transport/test_identity_cipher.rb
+++ b/test/transport/test_identity_cipher.rb
@@ -2,7 +2,6 @@ require 'common'
require 'net/ssh/transport/identity_cipher'
module Transport
-
class TestIdentityCipher < NetSSHTest
def test_block_size_should_be_8
assert_equal 8, cipher.block_size
@@ -34,5 +33,4 @@ module Transport
Net::SSH::Transport::IdentityCipher
end
end
-
end
diff --git a/test/transport/test_packet_stream.rb b/test/transport/test_packet_stream.rb
index 25c6b32..2921765 100644
--- a/test/transport/test_packet_stream.rb
+++ b/test/transport/test_packet_stream.rb
@@ -1,11 +1,10 @@
# encoding: ASCII-8BIT
-require 'common'
+require_relative '../common'
require 'timeout'
require 'net/ssh/transport/packet_stream'
module Transport
-
class TestPacketStream < NetSSHTest # rubocop:disable Metrics/ClassLength
include Net::SSH::Transport::Constants
@@ -58,12 +57,12 @@ module Transport
end
def test_available_for_read_should_return_nontrue_when_self_is_not_ready
- IO.expects(:select).with([stream], nil, nil, 0).returns([[],[],[]])
+ IO.expects(:select).with([stream], nil, nil, 0).returns([[], [], []])
assert !stream.available_for_read?
end
def test_available_for_read_should_return_true_when_self_is_ready
- IO.expects(:select).with([stream], nil, nil, 0).returns([[self],[],[]])
+ IO.expects(:select).with([stream], nil, nil, 0).returns([[self], [], []])
assert stream.available_for_read?
end
@@ -135,7 +134,7 @@ module Transport
def test_next_packet_should_eventually_return_packet_when_non_blocking_and_partial_read
IO.stubs(:select).returns([[stream]])
- stream.stubs(:recv).returns(packet[0,10], packet[10..-1])
+ stream.stubs(:recv).returns(packet[0, 10], packet[10..-1])
assert_nil stream.next_packet(:nonblock)
packet = stream.next_packet(:nonblock)
assert_not_nil packet
@@ -160,7 +159,7 @@ module Transport
def test_next_packet_should_block_when_requested_until_entire_packet_is_available
IO.stubs(:select).returns([[stream]])
- stream.stubs(:recv).returns(packet[0,10], packet[10,20], packet[20..-1])
+ stream.stubs(:recv).returns(packet[0, 10], packet[10, 20], packet[20..-1])
packet = stream.next_packet(:block)
assert_not_nil packet
assert_equal DEBUG, packet.type
@@ -182,7 +181,7 @@ module Transport
end
def test_send_packet_should_enqueue_and_send_data_immediately
- stream.expects(:send).times(3).with { |a,b| a == stream.write_buffer && b == 0 }.returns(15)
+ stream.expects(:send).times(3).with { |a, b| a == stream.write_buffer && b == 0 }.returns(15)
IO.expects(:select).times(2).returns([[], [stream]])
stream.send_packet(ssh_packet)
assert !stream.pending_write?
@@ -1129,5 +1128,4 @@ module Transport
end
end
end
-
end
diff --git a/test/transport/test_server_version.rb b/test/transport/test_server_version.rb
index ae443cc..c4b92a3 100644
--- a/test/transport/test_server_version.rb
+++ b/test/transport/test_server_version.rb
@@ -42,7 +42,7 @@ module Transport
private
- def socket(good, version_header, raise_eot=false)
+ def socket(good, version_header, raise_eot = false)
socket = mock("socket")
socket.expects(:write).with("#{Net::SSH::Transport::ServerVersion::PROTO_VERSION}\r\n")
diff --git a/test/transport/test_session.rb b/test/transport/test_session.rb
index 1b3747a..7a26dfc 100644
--- a/test/transport/test_session.rb
+++ b/test/transport/test_session.rb
@@ -10,7 +10,6 @@ require 'logger'
Object.send(:undef_method, :verify) if Object.instance_methods.any? { |v| v.to_sym == :verify }
module Transport
-
class TestSession < NetSSHTest
include Net::SSH::Transport::Constants
@@ -403,7 +402,7 @@ module Transport
@algorithms ||= stub("algorithms", initialized?: true, allow?: true, start: true)
end
- def session(options={})
+ def session(options = {})
@session ||= begin
host = options.delete(:host) || TEST_HOST
if (proxy = options[:proxy])
@@ -421,5 +420,4 @@ module Transport
# version makes it look more like the session is being instantiated
alias session! session
end
-
end
diff --git a/test/transport/test_state.rb b/test/transport/test_state.rb
index aefd347..bc9b00d 100644
--- a/test/transport/test_state.rb
+++ b/test/transport/test_state.rb
@@ -4,7 +4,6 @@ require 'common'
require 'net/ssh/transport/state'
module Transport
-
class TestState < NetSSHTest
def setup
@socket = @state = @deflater = @inflater = nil
@@ -115,18 +114,20 @@ module Transport
end
def test_compress_when_compression_is_enabled_should_return_compressed_text
- state.set compression: :standard
+ state.set compression: :standard
# JRuby Zlib implementation (1.4 & 1.5) does not have byte-to-byte compatibility with MRI's.
# skip this test under JRuby.
return if defined?(JRUBY_VERSION)
+
assert_equal "x\234\312H\315\311\311WH-K-\252L\312O\251\004\000\000\000\377\377", state.compress("hello everybody")
end
def test_decompress_when_compression_is_enabled_should_return_decompressed_text
- state.set compression: :standard
+ state.set compression: :standard
# JRuby Zlib implementation (1.4 & 1.5) does not have byte-to-byte compatibility with MRI's.
# skip this test under JRuby.
return if defined?(JRUBY_VERSION)
+
assert_equal "hello everybody", state.decompress("x\234\312H\315\311\311WH-K-\252L\312O\251\004\000\000\000\377\377")
end
@@ -160,7 +161,7 @@ module Transport
private
- def deflater(level=Zlib::DEFAULT_COMPRESSION)
+ def deflater(level = Zlib::DEFAULT_COMPRESSION)
@deflater ||= Zlib::Deflate.new(level)
end
@@ -176,5 +177,4 @@ module Transport
@state ||= Net::SSH::Transport::State.new(socket, :test)
end
end
-
-end \ No newline at end of file
+end
diff --git a/test/verifiers/test_always.rb b/test/verifiers/test_always.rb
index 64547ff..c387d7f 100644
--- a/test/verifiers/test_always.rb
+++ b/test/verifiers/test_always.rb
@@ -10,31 +10,31 @@ class TestAlways < NetSSHTest
'foo'
end
assert_raises(Net::SSH::HostKeyUnknown) {
- secure_verifier.verify(session:OpenStruct.new(host_keys:host_keys))
+ secure_verifier.verify(session: OpenStruct.new(host_keys: host_keys))
}
end
def test_passess_if_sam
secure_verifier = Net::SSH::Verifiers::Always.new
- key = OpenStruct.new(ssh_type:'key_type',to_blob:'keyblob')
+ key = OpenStruct.new(ssh_type: 'key_type', to_blob: 'keyblob')
host_keys = [key]
def host_keys.host
'foo'
end
- secure_verifier.verify(session:OpenStruct.new(host_keys:host_keys), key:key)
+ secure_verifier.verify(session: OpenStruct.new(host_keys: host_keys), key: key)
end
def test_raises_mismatch_error_if_not_the_same
secure_verifier = Net::SSH::Verifiers::Always.new
- key_in_known_hosts = OpenStruct.new(ssh_type:'key_type',to_blob:'keyblob')
- key_actual = OpenStruct.new(ssh_type:'key_type',to_blob:'not keyblob')
+ key_in_known_hosts = OpenStruct.new(ssh_type: 'key_type', to_blob: 'keyblob')
+ key_actual = OpenStruct.new(ssh_type: 'key_type', to_blob: 'not keyblob')
host_keys = [key_in_known_hosts]
def host_keys.host
'foo'
end
assert_raises(Net::SSH::HostKeyMismatch) {
- secure_verifier.verify(session:OpenStruct.new(host_keys:host_keys), key:key_actual)
+ secure_verifier.verify(session: OpenStruct.new(host_keys: host_keys), key: key_actual)
}
end
diff --git a/test/win_integration/test_pageant.rb b/test/win_integration/test_pageant.rb
index 374433f..0a909a7 100644
--- a/test/win_integration/test_pageant.rb
+++ b/test/win_integration/test_pageant.rb
@@ -2,35 +2,35 @@ require_relative '../common'
require 'net/ssh/authentication/agent'
module Authentication
-
unless RUBY_PLATFORM == "java"
class TestPageapnt < NetSSHTest
def with_pagent
pageant_path = 'C:\ProgramData\chocolatey\lib\putty.portable\tools\pageant.exe'
raise "No pageant found at:#{pageant_path}" unless File.executable?(pageant_path)
+
pageant_pid = Process.spawn(pageant_path)
sleep 4
yield
ensure
Process.kill(9, pageant_pid)
end
-
+
def test_agent_should_be_able_to_negotiate_with_pagent
with_pagent do
agent.negotiate!
end
end
-
+
def test_agent_should_raise_without_pagent
assert_raises Net::SSH::Authentication::AgentNotAvailable do
agent.negotiate!
end
end
-
+
private
-
- def agent(auto=:connect)
+
+ def agent(auto = :connect)
@agent ||= begin
agent = Net::SSH::Authentication::Agent.new
agent.connect! if auto == :connect
@@ -40,5 +40,4 @@ module Authentication
end
end
-
end