hrr_rb_ssh 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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