hrr_rb_ssh 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +22 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE +201 -0
  8. data/README.md +47 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/demo/server.rb +134 -0
  13. data/hrr_rb_ssh.gemspec +27 -0
  14. data/lib/hrr_rb_ssh/authentication/authenticator.rb +16 -0
  15. data/lib/hrr_rb_ssh/authentication/method/none/context.rb +28 -0
  16. data/lib/hrr_rb_ssh/authentication/method/none.rb +38 -0
  17. data/lib/hrr_rb_ssh/authentication/method/password/context.rb +29 -0
  18. data/lib/hrr_rb_ssh/authentication/method/password.rb +37 -0
  19. data/lib/hrr_rb_ssh/authentication/method.rb +21 -0
  20. data/lib/hrr_rb_ssh/authentication.rb +107 -0
  21. data/lib/hrr_rb_ssh/closed_authentication_error.rb +7 -0
  22. data/lib/hrr_rb_ssh/closed_connection_error.rb +7 -0
  23. data/lib/hrr_rb_ssh/closed_transport_error.rb +7 -0
  24. data/lib/hrr_rb_ssh/compat.rb +65 -0
  25. data/lib/hrr_rb_ssh/connection/channel/proc_chain/chain_context.rb +22 -0
  26. data/lib/hrr_rb_ssh/connection/channel/proc_chain.rb +25 -0
  27. data/lib/hrr_rb_ssh/connection/channel/session/env/context.rb +43 -0
  28. data/lib/hrr_rb_ssh/connection/channel/session/env.rb +31 -0
  29. data/lib/hrr_rb_ssh/connection/channel/session/exec/context.rb +41 -0
  30. data/lib/hrr_rb_ssh/connection/channel/session/exec.rb +31 -0
  31. data/lib/hrr_rb_ssh/connection/channel/session/pty_req/context.rb +50 -0
  32. data/lib/hrr_rb_ssh/connection/channel/session/pty_req.rb +31 -0
  33. data/lib/hrr_rb_ssh/connection/channel/session/shell/context.rb +37 -0
  34. data/lib/hrr_rb_ssh/connection/channel/session/shell.rb +31 -0
  35. data/lib/hrr_rb_ssh/connection/channel/session/subsystem/context.rb +40 -0
  36. data/lib/hrr_rb_ssh/connection/channel/session/subsystem.rb +31 -0
  37. data/lib/hrr_rb_ssh/connection/channel/session.rb +31 -0
  38. data/lib/hrr_rb_ssh/connection/channel.rb +278 -0
  39. data/lib/hrr_rb_ssh/connection/request_handler.rb +18 -0
  40. data/lib/hrr_rb_ssh/connection.rb +170 -0
  41. data/lib/hrr_rb_ssh/logger.rb +52 -0
  42. data/lib/hrr_rb_ssh/message/001_ssh_msg_disconnect.rb +44 -0
  43. data/lib/hrr_rb_ssh/message/002_ssh_msg_ignore.rb +24 -0
  44. data/lib/hrr_rb_ssh/message/003_ssh_msg_unimplemented.rb +24 -0
  45. data/lib/hrr_rb_ssh/message/004_ssh_msg_debug.rb +26 -0
  46. data/lib/hrr_rb_ssh/message/005_ssh_msg_service_request.rb +24 -0
  47. data/lib/hrr_rb_ssh/message/006_ssh_msg_service_accept.rb +24 -0
  48. data/lib/hrr_rb_ssh/message/020_ssh_msg_kexinit.rb +51 -0
  49. data/lib/hrr_rb_ssh/message/021_ssh_msg_newkeys.rb +23 -0
  50. data/lib/hrr_rb_ssh/message/030_ssh_msg_kexdh_init.rb +24 -0
  51. data/lib/hrr_rb_ssh/message/031_ssh_msg_kexdh_reply.rb +26 -0
  52. data/lib/hrr_rb_ssh/message/050_ssh_msg_userauth_request.rb +58 -0
  53. data/lib/hrr_rb_ssh/message/051_ssh_msg_userauth_failure.rb +25 -0
  54. data/lib/hrr_rb_ssh/message/052_ssh_msg_userauth_success.rb +23 -0
  55. data/lib/hrr_rb_ssh/message/060_ssh_msg_userauth_pk_ok.rb +25 -0
  56. data/lib/hrr_rb_ssh/message/080_ssh_msg_global_request.rb +47 -0
  57. data/lib/hrr_rb_ssh/message/081_ssh_msg_request_success.rb +36 -0
  58. data/lib/hrr_rb_ssh/message/082_ssh_msg_request_failure.rb +23 -0
  59. data/lib/hrr_rb_ssh/message/090_ssh_msg_channel_open.rb +67 -0
  60. data/lib/hrr_rb_ssh/message/091_ssh_msg_channel_open_confirmation.rb +67 -0
  61. data/lib/hrr_rb_ssh/message/092_ssh_msg_channel_open_failure.rb +34 -0
  62. data/lib/hrr_rb_ssh/message/093_ssh_msg_channel_window_adjust.rb +25 -0
  63. data/lib/hrr_rb_ssh/message/094_ssh_msg_channel_data.rb +25 -0
  64. data/lib/hrr_rb_ssh/message/095_ssh_msg_channel_extended_data.rb +30 -0
  65. data/lib/hrr_rb_ssh/message/096_ssh_msg_channel_eof.rb +24 -0
  66. data/lib/hrr_rb_ssh/message/097_ssh_msg_channel_close.rb +24 -0
  67. data/lib/hrr_rb_ssh/message/098_ssh_msg_channel_request.rb +139 -0
  68. data/lib/hrr_rb_ssh/message/099_ssh_msg_channel_success.rb +24 -0
  69. data/lib/hrr_rb_ssh/message/100_ssh_msg_channel_failure.rb +24 -0
  70. data/lib/hrr_rb_ssh/message/codable.rb +67 -0
  71. data/lib/hrr_rb_ssh/message.rb +36 -0
  72. data/lib/hrr_rb_ssh/transport/compression_algorithm/none.rb +33 -0
  73. data/lib/hrr_rb_ssh/transport/compression_algorithm/zlib.rb +38 -0
  74. data/lib/hrr_rb_ssh/transport/compression_algorithm.rb +22 -0
  75. data/lib/hrr_rb_ssh/transport/constant.rb +11 -0
  76. data/lib/hrr_rb_ssh/transport/data_type.rb +163 -0
  77. data/lib/hrr_rb_ssh/transport/encryption_algorithm/aes_128_cbc.rb +73 -0
  78. data/lib/hrr_rb_ssh/transport/encryption_algorithm/none.rb +49 -0
  79. data/lib/hrr_rb_ssh/transport/encryption_algorithm.rb +22 -0
  80. data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman.rb +129 -0
  81. data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group14_sha1.rb +42 -0
  82. data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group1_sha1.rb +34 -0
  83. data/lib/hrr_rb_ssh/transport/kex_algorithm.rb +22 -0
  84. data/lib/hrr_rb_ssh/transport/mac_algorithm/hmac_sha1.rb +45 -0
  85. data/lib/hrr_rb_ssh/transport/mac_algorithm/none.rb +40 -0
  86. data/lib/hrr_rb_ssh/transport/mac_algorithm.rb +22 -0
  87. data/lib/hrr_rb_ssh/transport/mode.rb +11 -0
  88. data/lib/hrr_rb_ssh/transport/receiver.rb +75 -0
  89. data/lib/hrr_rb_ssh/transport/sender.rb +57 -0
  90. data/lib/hrr_rb_ssh/transport/sequence_number.rb +22 -0
  91. data/lib/hrr_rb_ssh/transport/server_host_key_algorithm/ssh_rsa.rb +108 -0
  92. data/lib/hrr_rb_ssh/transport/server_host_key_algorithm.rb +21 -0
  93. data/lib/hrr_rb_ssh/transport.rb +459 -0
  94. data/lib/hrr_rb_ssh/version.rb +6 -0
  95. data/lib/hrr_rb_ssh.rb +13 -0
  96. metadata +193 -0
@@ -0,0 +1,108 @@
1
+ # coding: utf-8
2
+ # vim: et ts=2 sw=2
3
+
4
+ require 'hrr_rb_ssh/logger'
5
+ require 'hrr_rb_ssh/transport/data_type'
6
+
7
+ module HrrRbSsh
8
+ class Transport
9
+ class ServerHostKeyAlgorithm
10
+ name_list = [
11
+ 'ssh-rsa'
12
+ ]
13
+
14
+ class SshRsa
15
+ SECRET_KEY = <<-EOB
16
+ -----BEGIN RSA PRIVATE KEY-----
17
+ MIIEpAIBAAKCAQEA71zHt9RvbXmxuOCWPKR65iBHO+a8M7Mfo4vRCs/dorZN7XL1
18
+ lYwjclvo0X1T39BRX+qJ2m4HB+7Vlef9YF7spYKm6czuSCYmJjD5X+PW5QYSGED1
19
+ fFSXwjTdDwJi1OKS4kL0Dd6zcSjlFxfjVLNCyUcix36XgDpoBLBFkDZd5P2ow3J6
20
+ WNanBasXrckjCk4M3kFclvmxl1O56bbV9VZq51ZqLjv/ZhOrE3WIPfrJGdZssODa
21
+ DnI6tM1puwZGVba9VaI8FfnuJcacJ3T9oEoXPY5W+kPZAw6dOARXnJTg+oZk/dBD
22
+ Bgej0aMO+1XM7HKz5BiqbhGGSXGas5zoefHbNwIDAQABAoIBAQDP2aQ/2EOuL8eI
23
+ /9TV8goafRr+RB1XU4r8zHOIzPnryhyfPX1OEDPToUXpa8gCiPWwsYxlVbfbRqTH
24
+ mHzoS2V5T5u7WE3t7tqfvVU+1C0OERhzYS0KeraRWLBA0VSbAeiEe5lL1f/CGr3c
25
+ MM0iBsvO1mu4ChBqs80RjTPKx7r/FStpWtqWN4kn+Bhj06qCqhftnudZdYFTHa/G
26
+ ia4YWOUH6dSIZKpE7oG53Gm/2ZdK2YiAgMOdrTQkvRzxuIa/RHaETj21hKpetmI7
27
+ TfS26RbU2t1Bf/fdFhtTqoAz+CrZEH7Z407ZO45fdc31zJAFIK2Zf3CDVnKwih3t
28
+ O0bEVSSpAoGBAP/zEWaTivdQtcemMRhFQBySgnStov+dsxnGBnTkWxVIU7VoFgyg
29
+ mgNRlWUxMf12mlfqBVRpx0/ALggHf5KFmbAZ+3qvKSLmfIVM5E9l5NKbZnCWtIqq
30
+ 1DN9kHPPOZn3uYvOs9Cpn7S6sa+rVZ82Mg8EZMsPesvFMOjrgNbMQxt7AoGBAO9o
31
+ 38VM0+M09sAgOhmqv+Esa2gUGw5n18o/fdmlZdnA+D2ntgr70AD6JUCSYrZgTJRq
32
+ HNMuKrbD6HyaPjVaxYJVCFJIcfV+nViZdE8cHh9WXQ/JP/T6nvNajCC8StvoQg4I
33
+ vAZFTzChoe2yrOsWXezn9QAecQ8L2WHDLImpayR1AoGADoc1jaUCVld2egas8ru7
34
+ j+OhFA5nGitRZz0eULRFl0eruLhXyA+1rkqLOFs6gzCgQi0+cDQw5A38jugeDasX
35
+ ti9DXwtiQmDi4I4kx3z5KBs6DVoAlX5s3R9be7dfhaXSGmV5P3bhYdjXDSmkio0A
36
+ +mk9b2lJhxeCVzZG8epWRNECgYB2KzGoVQ+Q6ieRFVcYLCuhnSc2rBXeumrMrSIV
37
+ N4paPOFKrWkxarF0igOxJ5AJrOafqvCnW/ZBV9l9BzUFaNRsTERbON7m6aQIg1Xh
38
+ ZmOH3Dz6+b7T0JB8VYks70OT38Qa4TzNa5B21JD0nmizcMrTkHphoKT1ZEfb9VYa
39
+ bMExsQKBgQDoSpo/ZP8+dwR1A/gcu2K5Ie47c3WgKw7qQMarxqzTeS8Xu6/KAn+J
40
+ Ka2zIvoHhxlhXFBRhp+FIaFlYRR38gHeNxCoUylpboCUyMkHOsOP43AiKsmbNK20
41
+ vzTNM3SFzgt3bHkdEtDLc64aoBX+dHOot6u71XLZrshnHPtiZ0C/ZA==
42
+ -----END RSA PRIVATE KEY-----
43
+ EOB
44
+
45
+ KEY_FORMAT_DEFINITION = [
46
+ ['string', 'ssh-rsa'],
47
+ ['mpint', 'e'],
48
+ ['mpint', 'n'],
49
+ ]
50
+
51
+ SIGN_DEFINITION = [
52
+ ['string', 'ssh-rsa'],
53
+ ['string', 'rsa_signature_blob'],
54
+ ]
55
+
56
+ def initialize
57
+ @logger = HrrRbSsh::Logger.new self.class.name
58
+
59
+ @rsa = OpenSSL::PKey::RSA.new SECRET_KEY
60
+ end
61
+
62
+ def encode definition, payload
63
+ definition.map{ |data_type, field_name|
64
+ field_value = if payload[field_name].instance_of? ::Proc then payload[field_name].call else payload[field_name] end
65
+ HrrRbSsh::Transport::DataType[data_type].encode( field_value )
66
+ }.join
67
+ end
68
+
69
+ def decode definition, payload
70
+ payload_io = StringIO.new payload, 'r'
71
+ definition.map{ |data_type, field_name|
72
+ [
73
+ field_name,
74
+ HrrRbSsh::Transport::DataType[data_type].decode( payload_io )
75
+ ]
76
+ }.to_h
77
+ end
78
+
79
+ def server_public_host_key
80
+ payload = {
81
+ 'ssh-rsa' => 'ssh-rsa',
82
+ 'e' => @rsa.e.to_i,
83
+ 'n' => @rsa.n.to_i,
84
+ }
85
+ encode KEY_FORMAT_DEFINITION, payload
86
+ end
87
+
88
+ def sign digest, data
89
+ payload = {
90
+ 'ssh-rsa' => 'ssh-rsa',
91
+ 'rsa_signature_blob' => @rsa.sign(digest, data),
92
+ }
93
+ encode SIGN_DEFINITION, payload
94
+ end
95
+
96
+ def verify digest, sign, data
97
+ payload = decode SIGN_DEFINITION, sign
98
+ payload['ssh-rsa'] == 'ssh-rsa' && @rsa.verify(digest, payload['rsa_signature_blob'], data)
99
+ end
100
+ end
101
+
102
+ @@list ||= Hash.new
103
+ name_list.each do |name|
104
+ @@list[name] = SshRsa
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ # vim: et ts=2 sw=2
3
+
4
+ require 'hrr_rb_ssh/logger'
5
+ require 'hrr_rb_ssh/transport/server_host_key_algorithm/ssh_rsa'
6
+
7
+ module HrrRbSsh
8
+ class Transport
9
+ class ServerHostKeyAlgorithm
10
+ @@list ||= Hash.new
11
+
12
+ def self.[] key
13
+ @@list[key]
14
+ end
15
+
16
+ def self.name_list
17
+ @@list.keys
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,459 @@
1
+ # coding: utf-8
2
+ # vim: et ts=2 sw=2
3
+
4
+ require 'hrr_rb_ssh/version'
5
+ require 'hrr_rb_ssh/logger'
6
+ require 'hrr_rb_ssh/message'
7
+ require 'hrr_rb_ssh/closed_transport_error'
8
+ require 'hrr_rb_ssh/transport/constant'
9
+ require 'hrr_rb_ssh/transport/mode'
10
+ require 'hrr_rb_ssh/transport/data_type'
11
+ require 'hrr_rb_ssh/transport/sequence_number'
12
+ require 'hrr_rb_ssh/transport/sender'
13
+ require 'hrr_rb_ssh/transport/receiver'
14
+ require 'hrr_rb_ssh/transport/kex_algorithm'
15
+ require 'hrr_rb_ssh/transport/server_host_key_algorithm'
16
+ require 'hrr_rb_ssh/transport/encryption_algorithm'
17
+ require 'hrr_rb_ssh/transport/mac_algorithm'
18
+ require 'hrr_rb_ssh/transport/compression_algorithm'
19
+
20
+ module HrrRbSsh
21
+ class Transport
22
+ include Constant
23
+
24
+ attr_reader \
25
+ :io,
26
+ :incoming_sequence_number,
27
+ :outgoing_sequence_number,
28
+ :server_host_key_algorithm,
29
+ :incoming_encryption_algorithm,
30
+ :incoming_mac_algorithm,
31
+ :incoming_compression_algorithm,
32
+ :outgoing_encryption_algorithm,
33
+ :outgoing_mac_algorithm,
34
+ :outgoing_compression_algorithm,
35
+ :v_c,
36
+ :v_s,
37
+ :i_c,
38
+ :i_s,
39
+ :session_id
40
+
41
+ def initialize io, mode
42
+ @io = io
43
+ @mode = mode
44
+
45
+ @logger = HrrRbSsh::Logger.new self.class.name
46
+
47
+ @closed = nil
48
+ @disconnected = nil
49
+
50
+ @sender = HrrRbSsh::Transport::Sender.new
51
+ @receiver = HrrRbSsh::Transport::Receiver.new
52
+
53
+ @send_queue = Queue.new
54
+ @receive_queue = Queue.new
55
+
56
+ @sender_thread = nil
57
+ @receiver_thread = nil
58
+
59
+ @local_version = "SSH-2.0-HrrRbSsh-#{HrrRbSsh::VERSION}".force_encoding(Encoding::ASCII_8BIT)
60
+ @remote_version = "".force_encoding(Encoding::ASCII_8BIT)
61
+
62
+ @incoming_sequence_number = HrrRbSsh::Transport::SequenceNumber.new
63
+ @outgoing_sequence_number = HrrRbSsh::Transport::SequenceNumber.new
64
+
65
+ @acceptable_services = Array.new
66
+
67
+ initialize_local_algorithms
68
+ initialize_algorithms
69
+ end
70
+
71
+ def register_acceptable_service service_name
72
+ @acceptable_services.push service_name
73
+ end
74
+
75
+ def send payload
76
+ begin
77
+ @send_queue.enq payload
78
+ rescue ClosedQueueError => e
79
+ raise HrrRbSsh::ClosedTransportError
80
+ end
81
+ end
82
+
83
+ def receive
84
+ payload = @receive_queue.deq
85
+ if @receive_queue.closed?
86
+ raise HrrRbSsh::ClosedTransportError
87
+ end
88
+ payload
89
+ end
90
+
91
+ def start
92
+ @logger.info("start transport")
93
+
94
+ exchange_version
95
+ exchange_key
96
+
97
+ case @mode
98
+ when HrrRbSsh::Transport::Mode::SERVER
99
+ verify_service_request
100
+ end
101
+
102
+ @closed = false
103
+
104
+ @sender_thread = sender_thread
105
+ @receiver_thread = receiver_thread
106
+
107
+ @logger.info("transport started")
108
+ end
109
+
110
+ def close
111
+ return if @closed
112
+ @logger.info("close transport")
113
+ @closed = true
114
+ @send_queue.close
115
+ @receive_queue.close
116
+ disconnect
117
+ @logger.info("transport closed")
118
+ end
119
+
120
+ def closed?
121
+ @closed
122
+ end
123
+
124
+ def disconnect
125
+ return if @disconnected
126
+ @logger.info("disconnect transport")
127
+ @disconnected = true
128
+ begin
129
+ send_disconnect
130
+ rescue IOError
131
+ @logger.warn("IO is closed")
132
+ rescue => e
133
+ @logger.error([e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join)
134
+ end
135
+ @logger.info("transport disconnected")
136
+ end
137
+
138
+ def exchange_version
139
+ send_version
140
+ receive_version
141
+
142
+ update_version_strings
143
+ end
144
+
145
+ def exchange_key
146
+ send_kexinit
147
+ receive_kexinit
148
+
149
+ update_kex_and_server_host_key_algorithms
150
+
151
+ case @mode
152
+ when HrrRbSsh::Transport::Mode::SERVER
153
+ receive_kexdh_init
154
+ send_kexdh_reply
155
+
156
+ send_newkeys
157
+ receive_newkeys
158
+ end
159
+ end
160
+
161
+ def verify_service_request
162
+ service_request_message = receive_service_request
163
+ service_name = service_request_message['service name']
164
+ if @acceptable_services.include? service_name
165
+ send_service_accept service_name
166
+ else
167
+ close
168
+ end
169
+ end
170
+
171
+ def sender_thread
172
+ Thread.start {
173
+ @logger.info("start sender thread")
174
+ loop do
175
+ begin
176
+ payload = @send_queue.deq
177
+ if @send_queue.closed?
178
+ @logger.info("closing sender thread")
179
+ break
180
+ end
181
+ @sender.send self, payload
182
+ rescue => e
183
+ @logger.error([e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join)
184
+ close
185
+ end
186
+ end
187
+ @logger.info("sender thread closed")
188
+ }
189
+ end
190
+
191
+ def receiver_thread
192
+ Thread.start {
193
+ @logger.info("start receiver thread")
194
+ loop do
195
+ if @receive_queue.closed?
196
+ @logger.info("closing receiver thread")
197
+ break
198
+ end
199
+ begin
200
+ payload = @receiver.receive self
201
+ case payload[0,1].unpack("C")[0]
202
+ when HrrRbSsh::Message::SSH_MSG_DISCONNECT::VALUE
203
+ message = HrrRbSsh::Message::SSH_MSG_DISCONNECT.decode payload
204
+ @logger.debug("received disconnect message: #{message.inspect}")
205
+ @disconnected = true
206
+ close
207
+ when HrrRbSsh::Message::SSH_MSG_IGNORE::VALUE
208
+ message = HrrRbSsh::Message::SSH_MSG_IGNORE.decode payload
209
+ @logger.debug("received ignore message: #{message.inspect}")
210
+ when HrrRbSsh::Message::SSH_MSG_UNIMPLEMENTED::VALUE
211
+ message = HrrRbSsh::Message::SSH_MSG_UNIMPLEMENTED.decode payload
212
+ @logger.debug("received unimplemented message: #{message.inspect}")
213
+ when HrrRbSsh::Message::SSH_MSG_DEBUG::VALUE
214
+ message = HrrRbSsh::Message::SSH_MSG_DEBUG.decode payload
215
+ @logger.debug("received debug message: #{message.inspect}")
216
+ else
217
+ @receive_queue.enq payload
218
+ end
219
+ rescue EOFError => e
220
+ close
221
+ rescue => e
222
+ @logger.error([e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join)
223
+ close
224
+ end
225
+ end
226
+ @logger.info("receiver thread closed")
227
+ }
228
+ end
229
+
230
+ def initialize_local_algorithms
231
+ @local_kex_algorithms = HrrRbSsh::Transport::KexAlgorithm.name_list
232
+ @local_server_host_key_algorithms = HrrRbSsh::Transport::ServerHostKeyAlgorithm.name_list
233
+ @local_encryption_algorithms_client_to_server = HrrRbSsh::Transport::EncryptionAlgorithm.name_list
234
+ @local_encryption_algorithms_server_to_client = HrrRbSsh::Transport::EncryptionAlgorithm.name_list
235
+ @local_mac_algorithms_client_to_server = HrrRbSsh::Transport::MacAlgorithm.name_list
236
+ @local_mac_algorithms_server_to_client = HrrRbSsh::Transport::MacAlgorithm.name_list
237
+ @local_compression_algorithms_client_to_server = HrrRbSsh::Transport::CompressionAlgorithm.name_list
238
+ @local_compression_algorithms_server_to_client = HrrRbSsh::Transport::CompressionAlgorithm.name_list
239
+ end
240
+
241
+ def initialize_algorithms
242
+ @incoming_encryption_algorithm = HrrRbSsh::Transport::EncryptionAlgorithm['none'].new
243
+ @incoming_mac_algorithm = HrrRbSsh::Transport::MacAlgorithm['none'].new
244
+ @incoming_compression_algorithm = HrrRbSsh::Transport::CompressionAlgorithm['none'].new
245
+
246
+ @outgoing_encryption_algorithm = HrrRbSsh::Transport::EncryptionAlgorithm['none'].new
247
+ @outgoing_mac_algorithm = HrrRbSsh::Transport::MacAlgorithm['none'].new
248
+ @outgoing_compression_algorithm = HrrRbSsh::Transport::CompressionAlgorithm['none'].new
249
+ end
250
+
251
+ def send_version
252
+ @io.write (@local_version + CR + LF)
253
+ end
254
+
255
+ def receive_version
256
+ tmp_str = String.new
257
+ loop do
258
+ tmp_str << @io.read(1)
259
+ if tmp_str =~ /#{CR}#{LF}/
260
+ if tmp_str =~ /^SSH-/
261
+ @remote_version = tmp_str.match( /(:?SSH-.+)#{CR}#{LF}/ )[1]
262
+ break
263
+ else
264
+ tmp_str.clear
265
+ end
266
+ end
267
+ end
268
+ end
269
+
270
+ def update_version_strings
271
+ case @mode
272
+ when HrrRbSsh::Transport::Mode::SERVER
273
+ @v_c = @remote_version
274
+ @v_s = @local_version
275
+ when HrrRbSsh::Transport::Mode::CLIENT
276
+ @v_c = @local_version
277
+ @v_s = @remote_version
278
+ end
279
+ end
280
+
281
+ def send_disconnect
282
+ message = {
283
+ "SSH_MSG_DISCONNECT" => 1,
284
+ "reason code" => HrrRbSsh::Message::SSH_MSG_DISCONNECT::ReasonCode::SSH_DISCONNECT_BY_APPLICATION,
285
+ "description" => "disconnected by user",
286
+ "language tag" => ""
287
+ }
288
+ payload = HrrRbSsh::Message::SSH_MSG_DISCONNECT.encode message
289
+ @sender.send self, payload
290
+ end
291
+
292
+ def send_kexinit
293
+ message = {
294
+ 'SSH_MSG_KEXINIT' => HrrRbSsh::Message::SSH_MSG_KEXINIT::VALUE,
295
+ 'cookie (random byte)' => lambda { rand(0x01_00) },
296
+ 'kex_algorithms' => @local_kex_algorithms,
297
+ 'server_host_key_algorithms' => @local_server_host_key_algorithms,
298
+ 'encryption_algorithms_client_to_server' => @local_encryption_algorithms_client_to_server,
299
+ 'encryption_algorithms_server_to_client' => @local_encryption_algorithms_server_to_client,
300
+ 'mac_algorithms_client_to_server' => @local_mac_algorithms_client_to_server,
301
+ 'mac_algorithms_server_to_client' => @local_mac_algorithms_server_to_client,
302
+ 'compression_algorithms_client_to_server' => @local_compression_algorithms_client_to_server,
303
+ 'compression_algorithms_server_to_client' => @local_compression_algorithms_server_to_client,
304
+ 'languages_client_to_server' => [],
305
+ 'languages_server_to_client' => [],
306
+ 'first_kex_packet_follows' => false,
307
+ '0 (reserved for future extension)' => 0,
308
+ }
309
+ payload = HrrRbSsh::Message::SSH_MSG_KEXINIT.encode message
310
+ @sender.send self, payload
311
+
312
+ case @mode
313
+ when HrrRbSsh::Transport::Mode::SERVER
314
+ @i_s = payload
315
+ when HrrRbSsh::Transport::Mode::CLIENT
316
+ @i_c = payload
317
+ end
318
+ end
319
+
320
+ def receive_kexinit
321
+ payload = @receiver.receive self
322
+
323
+ case @mode
324
+ when HrrRbSsh::Transport::Mode::SERVER
325
+ @i_c = payload
326
+ when HrrRbSsh::Transport::Mode::CLIENT
327
+ @i_s = payload
328
+ end
329
+
330
+ message = HrrRbSsh::Message::SSH_MSG_KEXINIT.decode payload
331
+
332
+ update_remote_algorithms message
333
+ end
334
+
335
+ def receive_kexdh_init
336
+ payload = @receiver.receive self
337
+ message = HrrRbSsh::Message::SSH_MSG_KEXDH_INIT.decode payload
338
+
339
+ @kex_algorithm.set_e message['e']
340
+
341
+ @session_id ||= @kex_algorithm.hash self
342
+ end
343
+
344
+ def send_kexdh_reply
345
+ message = {
346
+ 'SSH_MSG_KEXDH_REPLY' => HrrRbSsh::Message::SSH_MSG_KEXDH_REPLY::VALUE,
347
+ 'server public host key and certificates (K_S)' => @server_host_key_algorithm.server_public_host_key,
348
+ 'f' => @kex_algorithm.pub_key,
349
+ 'signature of H' => @kex_algorithm.sign(self),
350
+ }
351
+ payload = HrrRbSsh::Message::SSH_MSG_KEXDH_REPLY.encode message
352
+ @sender.send self, payload
353
+ end
354
+
355
+ def send_newkeys
356
+ message = {
357
+ 'SSH_MSG_NEWKEYS' => HrrRbSsh::Message::SSH_MSG_NEWKEYS::VALUE,
358
+ }
359
+ payload = HrrRbSsh::Message::SSH_MSG_NEWKEYS.encode message
360
+ @sender.send self, payload
361
+ end
362
+
363
+ def receive_newkeys
364
+ payload = @receiver.receive self
365
+ message = HrrRbSsh::Message::SSH_MSG_NEWKEYS.decode payload
366
+
367
+ update_encryption_mac_compression_algorithms
368
+ end
369
+
370
+ def receive_service_request
371
+ payload = @receiver.receive self
372
+ message = HrrRbSsh::Message::SSH_MSG_SERVICE_REQUEST.decode payload
373
+
374
+ message
375
+ end
376
+
377
+ def send_service_accept service_name
378
+ message = {
379
+ 'SSH_MSG_SERVICE_ACCEPT' => HrrRbSsh::Message::SSH_MSG_SERVICE_ACCEPT::VALUE,
380
+ 'service name' => service_name,
381
+ }
382
+ payload = HrrRbSsh::Message::SSH_MSG_SERVICE_ACCEPT.encode message
383
+ @sender.send self, payload
384
+ end
385
+
386
+ def update_remote_algorithms message
387
+ @remote_kex_algorithms = message['kex_algorithms']
388
+ @remote_server_host_key_algorithms = message['server_host_key_algorithms']
389
+ @remote_encryption_algorithms_client_to_server = message['encryption_algorithms_client_to_server']
390
+ @remote_encryption_algorithms_server_to_client = message['encryption_algorithms_server_to_client']
391
+ @remote_mac_algorithms_client_to_server = message['mac_algorithms_client_to_server']
392
+ @remote_mac_algorithms_server_to_client = message['mac_algorithms_server_to_client']
393
+ @remote_compression_algorithms_client_to_server = message['compression_algorithms_client_to_server']
394
+ @remote_compression_algorithms_server_to_client = message['compression_algorithms_server_to_client']
395
+ end
396
+
397
+ def update_kex_and_server_host_key_algorithms
398
+ case @mode
399
+ when HrrRbSsh::Transport::Mode::SERVER
400
+ kex_algorithm_name = @remote_kex_algorithms.find{ |a| @local_kex_algorithms.include? a } or raise
401
+ server_host_key_algorithm_name = @remote_server_host_key_algorithms.find{ |a| @local_server_host_key_algorithms.include? a } or raise
402
+ when HrrRbSsh::Transport::Mode::CLIENT
403
+ kex_algorithm_name = @local_kex_algorithms.find{ |a| @remote_kex_algorithms.include? a } or raise
404
+ server_host_key_algorithm_name = @local_server_host_key_algorithms.find{ |a| @remote_server_host_key_algorithms.include? a } or raise
405
+ end
406
+
407
+ @kex_algorithm = HrrRbSsh::Transport::KexAlgorithm[kex_algorithm_name].new
408
+ @server_host_key_algorithm = HrrRbSsh::Transport::ServerHostKeyAlgorithm[server_host_key_algorithm_name].new
409
+ end
410
+
411
+ def update_encryption_mac_compression_algorithms
412
+ update_encryption_algorithm
413
+ update_mac_algorithm
414
+ update_compression_algorithm
415
+ end
416
+
417
+ def update_encryption_algorithm
418
+ case @mode
419
+ when HrrRbSsh::Transport::Mode::SERVER
420
+ encryption_algorithm_c_to_s_name = @remote_encryption_algorithms_client_to_server.find{ |a| @local_encryption_algorithms_client_to_server.include? a } or raise
421
+ encryption_algorithm_s_to_c_name = @remote_encryption_algorithms_server_to_client.find{ |a| @local_encryption_algorithms_server_to_client.include? a } or raise
422
+ incoming_encryption_algorithm_name = encryption_algorithm_c_to_s_name
423
+ outgoing_encryption_algorithm_name = encryption_algorithm_s_to_c_name
424
+ incoming_crpt_iv = @kex_algorithm.iv_c_to_s self, incoming_encryption_algorithm_name
425
+ outgoing_crpt_iv = @kex_algorithm.iv_s_to_c self, outgoing_encryption_algorithm_name
426
+ incoming_crpt_key = @kex_algorithm.key_c_to_s self, incoming_encryption_algorithm_name
427
+ outgoing_crpt_key = @kex_algorithm.key_s_to_c self, outgoing_encryption_algorithm_name
428
+ end
429
+ @incoming_encryption_algorithm = HrrRbSsh::Transport::EncryptionAlgorithm[incoming_encryption_algorithm_name].new incoming_crpt_iv, incoming_crpt_key
430
+ @outgoing_encryption_algorithm = HrrRbSsh::Transport::EncryptionAlgorithm[outgoing_encryption_algorithm_name].new outgoing_crpt_iv, outgoing_crpt_key
431
+ end
432
+
433
+ def update_mac_algorithm
434
+ case @mode
435
+ when HrrRbSsh::Transport::Mode::SERVER
436
+ mac_algorithm_c_to_s_name = @remote_mac_algorithms_client_to_server.find{ |a| @local_mac_algorithms_client_to_server.include? a } or raise
437
+ mac_algorithm_s_to_c_name = @remote_mac_algorithms_server_to_client.find{ |a| @local_mac_algorithms_server_to_client.include? a } or raise
438
+ incoming_mac_algorithm_name = mac_algorithm_c_to_s_name
439
+ outgoing_mac_algorithm_name = mac_algorithm_s_to_c_name
440
+ incoming_mac_key = @kex_algorithm.mac_c_to_s self, incoming_mac_algorithm_name
441
+ outgoing_mac_key = @kex_algorithm.mac_s_to_c self, outgoing_mac_algorithm_name
442
+ end
443
+ @incoming_mac_algorithm = HrrRbSsh::Transport::MacAlgorithm[incoming_mac_algorithm_name].new incoming_mac_key
444
+ @outgoing_mac_algorithm = HrrRbSsh::Transport::MacAlgorithm[outgoing_mac_algorithm_name].new outgoing_mac_key
445
+ end
446
+
447
+ def update_compression_algorithm
448
+ case @mode
449
+ when HrrRbSsh::Transport::Mode::SERVER
450
+ compression_algorithm_c_to_s_name = @remote_compression_algorithms_client_to_server.find{ |a| @local_compression_algorithms_client_to_server.include? a } or raise
451
+ compression_algorithm_s_to_c_name = @remote_compression_algorithms_server_to_client.find{ |a| @local_compression_algorithms_server_to_client.include? a } or raise
452
+ incoming_compression_algorithm_name = compression_algorithm_c_to_s_name
453
+ outgoing_compression_algorithm_name = compression_algorithm_s_to_c_name
454
+ end
455
+ @incoming_compression_algorithm = HrrRbSsh::Transport::CompressionAlgorithm[incoming_compression_algorithm_name].new
456
+ @outgoing_compression_algorithm = HrrRbSsh::Transport::CompressionAlgorithm[outgoing_compression_algorithm_name].new
457
+ end
458
+ end
459
+ end
@@ -0,0 +1,6 @@
1
+ # coding: utf-8
2
+ # vim: et ts=2 sw=2
3
+
4
+ module HrrRbSsh
5
+ VERSION = "0.1.0"
6
+ end
data/lib/hrr_rb_ssh.rb ADDED
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+ # vim: et ts=2 sw=2
3
+
4
+ require "hrr_rb_ssh/version"
5
+ require "hrr_rb_ssh/compat"
6
+ require "hrr_rb_ssh/logger"
7
+ require "hrr_rb_ssh/transport"
8
+ require "hrr_rb_ssh/authentication"
9
+ require "hrr_rb_ssh/connection"
10
+
11
+ module HrrRbSsh
12
+ # Your code goes here...
13
+ end