eximius-net-ssh 6.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +6 -0
  3. data/.github/config/rubocop_linter_action.yml +4 -0
  4. data/.github/workflows/ci-with-docker.yml +44 -0
  5. data/.github/workflows/ci.yml +87 -0
  6. data/.github/workflows/rubocop.yml +13 -0
  7. data/.gitignore +13 -0
  8. data/.rubocop.yml +22 -0
  9. data/.rubocop_todo.yml +1072 -0
  10. data/CHANGES.txt +698 -0
  11. data/Dockerfile +27 -0
  12. data/Dockerfile.openssl3 +17 -0
  13. data/Gemfile +13 -0
  14. data/Gemfile.noed25519 +12 -0
  15. data/ISSUE_TEMPLATE.md +30 -0
  16. data/LICENSE.txt +19 -0
  17. data/Manifest +132 -0
  18. data/README.md +293 -0
  19. data/Rakefile +105 -0
  20. data/THANKS.txt +110 -0
  21. data/appveyor.yml +58 -0
  22. data/docker-compose.yml +23 -0
  23. data/lib/net/ssh/authentication/agent.rb +284 -0
  24. data/lib/net/ssh/authentication/certificate.rb +183 -0
  25. data/lib/net/ssh/authentication/constants.rb +20 -0
  26. data/lib/net/ssh/authentication/ed25519.rb +185 -0
  27. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  28. data/lib/net/ssh/authentication/key_manager.rb +310 -0
  29. data/lib/net/ssh/authentication/methods/abstract.rb +79 -0
  30. data/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
  31. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
  32. data/lib/net/ssh/authentication/methods/none.rb +34 -0
  33. data/lib/net/ssh/authentication/methods/password.rb +80 -0
  34. data/lib/net/ssh/authentication/methods/publickey.rb +137 -0
  35. data/lib/net/ssh/authentication/pageant.rb +497 -0
  36. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  37. data/lib/net/ssh/authentication/session.rb +165 -0
  38. data/lib/net/ssh/buffer.rb +440 -0
  39. data/lib/net/ssh/buffered_io.rb +202 -0
  40. data/lib/net/ssh/config.rb +406 -0
  41. data/lib/net/ssh/connection/channel.rb +695 -0
  42. data/lib/net/ssh/connection/constants.rb +33 -0
  43. data/lib/net/ssh/connection/event_loop.rb +123 -0
  44. data/lib/net/ssh/connection/keepalive.rb +59 -0
  45. data/lib/net/ssh/connection/session.rb +712 -0
  46. data/lib/net/ssh/connection/term.rb +180 -0
  47. data/lib/net/ssh/errors.rb +106 -0
  48. data/lib/net/ssh/key_factory.rb +218 -0
  49. data/lib/net/ssh/known_hosts.rb +265 -0
  50. data/lib/net/ssh/loggable.rb +62 -0
  51. data/lib/net/ssh/packet.rb +106 -0
  52. data/lib/net/ssh/prompt.rb +62 -0
  53. data/lib/net/ssh/proxy/command.rb +123 -0
  54. data/lib/net/ssh/proxy/errors.rb +16 -0
  55. data/lib/net/ssh/proxy/http.rb +98 -0
  56. data/lib/net/ssh/proxy/https.rb +50 -0
  57. data/lib/net/ssh/proxy/jump.rb +54 -0
  58. data/lib/net/ssh/proxy/socks4.rb +67 -0
  59. data/lib/net/ssh/proxy/socks5.rb +140 -0
  60. data/lib/net/ssh/service/forward.rb +426 -0
  61. data/lib/net/ssh/test/channel.rb +147 -0
  62. data/lib/net/ssh/test/extensions.rb +173 -0
  63. data/lib/net/ssh/test/kex.rb +46 -0
  64. data/lib/net/ssh/test/local_packet.rb +53 -0
  65. data/lib/net/ssh/test/packet.rb +101 -0
  66. data/lib/net/ssh/test/remote_packet.rb +40 -0
  67. data/lib/net/ssh/test/script.rb +180 -0
  68. data/lib/net/ssh/test/socket.rb +65 -0
  69. data/lib/net/ssh/test.rb +94 -0
  70. data/lib/net/ssh/transport/algorithms.rb +502 -0
  71. data/lib/net/ssh/transport/cipher_factory.rb +103 -0
  72. data/lib/net/ssh/transport/constants.rb +40 -0
  73. data/lib/net/ssh/transport/ctr.rb +115 -0
  74. data/lib/net/ssh/transport/hmac/abstract.rb +97 -0
  75. data/lib/net/ssh/transport/hmac/md5.rb +10 -0
  76. data/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
  77. data/lib/net/ssh/transport/hmac/none.rb +13 -0
  78. data/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
  79. data/lib/net/ssh/transport/hmac/sha1.rb +11 -0
  80. data/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
  81. data/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
  82. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
  83. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  84. data/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
  85. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
  86. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  87. data/lib/net/ssh/transport/hmac.rb +47 -0
  88. data/lib/net/ssh/transport/identity_cipher.rb +57 -0
  89. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  90. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  91. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  92. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
  96. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
  97. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
  99. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
  100. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
  101. data/lib/net/ssh/transport/kex.rb +31 -0
  102. data/lib/net/ssh/transport/key_expander.rb +30 -0
  103. data/lib/net/ssh/transport/openssl.rb +262 -0
  104. data/lib/net/ssh/transport/packet_stream.rb +280 -0
  105. data/lib/net/ssh/transport/server_version.rb +77 -0
  106. data/lib/net/ssh/transport/session.rb +354 -0
  107. data/lib/net/ssh/transport/state.rb +208 -0
  108. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  109. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  110. data/lib/net/ssh/verifiers/always.rb +58 -0
  111. data/lib/net/ssh/verifiers/never.rb +19 -0
  112. data/lib/net/ssh/version.rb +70 -0
  113. data/lib/net/ssh.rb +330 -0
  114. data/net-ssh-public_cert.pem +20 -0
  115. data/net-ssh.gemspec +44 -0
  116. data/support/ssh_tunnel_bug.rb +65 -0
  117. metadata +277 -0
@@ -0,0 +1,77 @@
1
+ require 'net/ssh/prompt'
2
+ require 'net/ssh/authentication/methods/abstract'
3
+
4
+ module Net
5
+ module SSH
6
+ module Authentication
7
+ module Methods
8
+ # Implements the "keyboard-interactive" SSH authentication method.
9
+ class KeyboardInteractive < Abstract
10
+ USERAUTH_INFO_REQUEST = 60
11
+ USERAUTH_INFO_RESPONSE = 61
12
+
13
+ # Attempt to authenticate the given user for the given service.
14
+ def authenticate(next_service, username, password = nil)
15
+ debug { "trying keyboard-interactive" }
16
+ send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
17
+
18
+ prompter = nil
19
+ loop do
20
+ message = session.next_message
21
+
22
+ case message.type
23
+ when USERAUTH_SUCCESS
24
+ debug { "keyboard-interactive succeeded" }
25
+ prompter.success if prompter
26
+ return true
27
+ when USERAUTH_FAILURE
28
+ debug { "keyboard-interactive failed" }
29
+
30
+ raise Net::SSH::Authentication::DisallowedMethod unless
31
+ message[:authentications].split(/,/).include? 'keyboard-interactive'
32
+
33
+ return false unless interactive?
34
+
35
+ password = nil
36
+ debug { "retrying keyboard-interactive" }
37
+ send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
38
+ when USERAUTH_INFO_REQUEST
39
+ name = message.read_string
40
+ instruction = message.read_string
41
+ debug { "keyboard-interactive info request" }
42
+
43
+ if password.nil? && interactive? && prompter.nil?
44
+ prompter = prompt.start(type: 'keyboard-interactive', name: name, instruction: instruction)
45
+ end
46
+
47
+ _ = message.read_string # lang_tag
48
+ responses = []
49
+
50
+ message.read_long.times do
51
+ text = message.read_string
52
+ echo = message.read_bool
53
+ password_to_send = password || (prompter && prompter.ask(text, echo))
54
+ responses << password_to_send
55
+ end
56
+
57
+ # if the password failed the first time around, don't try
58
+ # and use it on subsequent requests.
59
+ password = nil
60
+
61
+ msg = Buffer.from(:byte, USERAUTH_INFO_RESPONSE, :long, responses.length, :string, responses)
62
+ send_message(msg)
63
+ else
64
+ raise Net::SSH::Exception, "unexpected reply in keyboard interactive: #{message.type} (#{message.inspect})"
65
+ end
66
+ end
67
+ end
68
+
69
+ def interactive?
70
+ options = session.transport.options || {}
71
+ !options[:non_interactive]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,34 @@
1
+ require 'net/ssh/errors'
2
+ require 'net/ssh/authentication/methods/abstract'
3
+
4
+ module Net
5
+ module SSH
6
+ module Authentication
7
+ module Methods
8
+ # Implements the "none" SSH authentication method.
9
+ class None < Abstract
10
+ # Attempt to authenticate as "none"
11
+ def authenticate(next_service, user = "", password = "")
12
+ send_message(userauth_request(user, next_service, "none"))
13
+ message = session.next_message
14
+
15
+ case message.type
16
+ when USERAUTH_SUCCESS
17
+ debug { "none succeeded" }
18
+ return true
19
+ when USERAUTH_FAILURE
20
+ debug { "none failed" }
21
+
22
+ raise Net::SSH::Authentication::DisallowedMethod unless
23
+ message[:authentications].split(/,/).include? 'none'
24
+
25
+ return false
26
+ else
27
+ raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,80 @@
1
+ require 'net/ssh/errors'
2
+ require 'net/ssh/prompt'
3
+ require 'net/ssh/authentication/methods/abstract'
4
+
5
+ module Net
6
+ module SSH
7
+ module Authentication
8
+ module Methods
9
+ # Implements the "password" SSH authentication method.
10
+ class Password < Abstract
11
+ # Attempt to authenticate the given user for the given service. If
12
+ # the password parameter is nil, this will ask for password
13
+ def authenticate(next_service, username, password = nil)
14
+ clear_prompter!
15
+ retries = 0
16
+ max_retries = get_max_retries
17
+ return false if !password && max_retries == 0
18
+
19
+ begin
20
+ password_to_send = password || ask_password(username)
21
+
22
+ send_message(userauth_request(username, next_service, "password", false, password_to_send))
23
+ message = session.next_message
24
+ retries += 1
25
+
26
+ if message.type == USERAUTH_FAILURE
27
+ debug { "password failed" }
28
+
29
+ raise Net::SSH::Authentication::DisallowedMethod unless
30
+ message[:authentications].split(/,/).include? 'password'
31
+
32
+ password = nil
33
+ end
34
+ end until (message.type != USERAUTH_FAILURE || retries >= max_retries)
35
+
36
+ case message.type
37
+ when USERAUTH_SUCCESS
38
+ debug { "password succeeded" }
39
+ @prompter.success if @prompter
40
+ return true
41
+ when USERAUTH_FAILURE
42
+ return false
43
+ when USERAUTH_PASSWD_CHANGEREQ
44
+ debug { "password change request received, failing" }
45
+ return false
46
+ else
47
+ raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ NUMBER_OF_PASSWORD_PROMPTS = 3
54
+
55
+ def clear_prompter!
56
+ @prompt_info = nil
57
+ @prompter = nil
58
+ end
59
+
60
+ def ask_password(username)
61
+ host = session.transport.host
62
+ prompt_info = { type: 'password', user: username, host: host }
63
+ if @prompt_info != prompt_info
64
+ @prompt_info = prompt_info
65
+ @prompter = prompt.start(prompt_info)
66
+ end
67
+ echo = false
68
+ @prompter.ask("#{username}@#{host}'s password:", echo)
69
+ end
70
+
71
+ def get_max_retries
72
+ options = session.transport.options || {}
73
+ result = options[:number_of_password_prompts] || NUMBER_OF_PASSWORD_PROMPTS
74
+ options[:non_interactive] ? 0 : result
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,137 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/errors'
3
+ require 'net/ssh/authentication/methods/abstract'
4
+
5
+ module Net
6
+ module SSH
7
+ module Authentication
8
+ module Methods
9
+ # Implements the "publickey" SSH authentication method.
10
+ class Publickey < Abstract
11
+ # Attempts to perform public-key authentication for the given
12
+ # username, trying each identity known to the key manager. If any of
13
+ # them succeed, returns +true+, otherwise returns +false+. This
14
+ # requires the presence of a key manager.
15
+ def authenticate(next_service, username, password = nil)
16
+ return false unless key_manager
17
+
18
+ key_manager.each_identity do |identity|
19
+ return true if authenticate_with(identity, next_service, username)
20
+ end
21
+
22
+ return false
23
+ end
24
+
25
+ private
26
+
27
+ # Builds a packet that contains the request formatted for sending
28
+ # a public-key request to the server.
29
+ def build_request(pub_key, username, next_service, alg, has_sig)
30
+ blob = Net::SSH::Buffer.new
31
+ blob.write_key pub_key
32
+
33
+ userauth_request(username, next_service, "publickey", has_sig,
34
+ alg, blob.to_s)
35
+ end
36
+
37
+ # Builds and sends a request formatted for a public-key
38
+ # authentication request.
39
+ def send_request(pub_key, username, next_service, alg, signature = nil)
40
+ msg = build_request(pub_key, username, next_service, alg,
41
+ !signature.nil?)
42
+ msg.write_string(signature) if signature
43
+ send_message(msg)
44
+ end
45
+
46
+ def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil)
47
+ debug { "trying publickey (#{identity.fingerprint})" }
48
+ send_request(identity, username, next_service, alg)
49
+
50
+ message = session.next_message
51
+
52
+ case message.type
53
+ when USERAUTH_PK_OK
54
+ buffer = build_request(identity, username, next_service, alg,
55
+ true)
56
+ sig_data = Net::SSH::Buffer.new
57
+ sig_data.write_string(session_id)
58
+ sig_data.append(buffer.to_s)
59
+
60
+ sig_blob = key_manager.sign(identity, sig_data, sig_alg)
61
+
62
+ send_request(identity, username, next_service, alg, sig_blob.to_s)
63
+ message = session.next_message
64
+
65
+ case message.type
66
+ when USERAUTH_SUCCESS
67
+ debug { "publickey succeeded (#{identity.fingerprint})" }
68
+ return true
69
+ when USERAUTH_FAILURE
70
+ debug { "publickey failed (#{identity.fingerprint})" }
71
+
72
+ raise Net::SSH::Authentication::DisallowedMethod unless
73
+ message[:authentications].split(/,/).include? 'publickey'
74
+
75
+ return false
76
+ else
77
+ raise Net::SSH::Exception,
78
+ "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
79
+ end
80
+
81
+ when USERAUTH_FAILURE
82
+ return false
83
+ when USERAUTH_SUCCESS
84
+ return true
85
+
86
+ else
87
+ raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
88
+ end
89
+ end
90
+
91
+ # Attempts to perform public-key authentication for the given
92
+ # username, with the given identity (public key). Returns +true+ if
93
+ # successful, or +false+ otherwise.
94
+ def authenticate_with(identity, next_service, username)
95
+ type = identity.ssh_type
96
+ if type == "ssh-rsa"
97
+ pubkey_algorithms.each do |pk_alg|
98
+ case pk_alg
99
+ when "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa"
100
+ if authenticate_with_alg(identity, next_service, username, pk_alg, pk_alg)
101
+ # success
102
+ return true
103
+ end
104
+ end
105
+ end
106
+ elsif type == "ssh-rsa-cert-v01@openssh.com"
107
+ pubkey_algorithms.each do |pk_alg|
108
+ case pk_alg
109
+ when "rsa-sha2-512-cert-v01@openssh.com"
110
+ if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-512")
111
+ # success
112
+ return true
113
+ end
114
+ when "rsa-sha2-256-cert-v01@openssh.com"
115
+ if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-256")
116
+ # success
117
+ return true
118
+ end
119
+ when "ssh-rsa-cert-v01@openssh.com"
120
+ if authenticate_with_alg(identity, next_service, username, pk_alg)
121
+ # success
122
+ return true
123
+ end
124
+ end
125
+ end
126
+ elsif authenticate_with_alg(identity, next_service, username, type)
127
+ # success
128
+ return true
129
+ end
130
+ # failure
131
+ return false
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end