hrr_rb_ssh 0.3.0.pre3 → 0.3.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.
@@ -11,12 +11,14 @@ module HrrRbSsh
11
11
  attr_reader \
12
12
  :username,
13
13
  :variables,
14
- :options
14
+ :options,
15
+ :mode
15
16
 
16
- def initialize authentication, options={}
17
+ def initialize authentication, mode, options={}
17
18
  @logger = Logger.new self.class.name
18
19
 
19
20
  @authentication = authentication
21
+ @mode = mode
20
22
  @options = options
21
23
 
22
24
  @global_request_handler = GlobalRequestHandler.new self
@@ -38,21 +40,31 @@ module HrrRbSsh
38
40
  def assign_channel
39
41
  i = 0
40
42
  res = nil
41
- loop do
43
+ while true
42
44
  break unless @channels.keys.include?(i)
43
45
  i += 1
44
46
  end
45
47
  i
46
48
  end
47
49
 
48
- def start
50
+ def start foreground: true
51
+ @logger.info { "start connection" }
49
52
  @authentication.start
50
53
  @closed = false
51
- connection_loop
54
+ @connection_loop_thread = connection_loop_thread
55
+ if foreground
56
+ @connection_loop_thread.join
57
+ end
58
+ end
59
+
60
+ def loop
61
+ @connection_loop_thread.join
52
62
  end
53
63
 
54
64
  def close
65
+ @logger.info { "closing connection" }
55
66
  @closed = true
67
+ @authentication.close
56
68
  @channels.values.each do |channel|
57
69
  begin
58
70
  channel.close
@@ -62,47 +74,58 @@ module HrrRbSsh
62
74
  end
63
75
  @channels.clear
64
76
  @global_request_handler.close
77
+ @connection_loop_thread.join unless @connection_loop_thread == Thread.current
78
+ @logger.info { "connection closed" }
65
79
  end
66
80
 
67
81
  def closed?
68
82
  @closed
69
83
  end
70
84
 
71
- def connection_loop
72
- @logger.info { "start connection" }
73
- loop do
85
+ def connection_loop_thread
86
+ @logger.info { "start connection loop" }
87
+ Thread.new do
74
88
  begin
75
- payload = @authentication.receive
76
- rescue Error::ClosedAuthentication => e
89
+ while true
90
+ begin
91
+ payload = @authentication.receive
92
+ rescue Error::ClosedAuthentication => e
93
+ @logger.info { "authentication closed" }
94
+ break
95
+ end
96
+ @username ||= @authentication.username
97
+ @variables ||= @authentication.variables
98
+ case payload[0,1].unpack("C")[0]
99
+ when Message::SSH_MSG_GLOBAL_REQUEST::VALUE
100
+ global_request payload
101
+ when Message::SSH_MSG_CHANNEL_OPEN::VALUE
102
+ channel_open payload
103
+ when Message::SSH_MSG_CHANNEL_OPEN_CONFIRMATION::VALUE
104
+ channel_open_confirmation payload
105
+ when Message::SSH_MSG_CHANNEL_REQUEST::VALUE
106
+ channel_request payload
107
+ when Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE
108
+ channel_window_adjust payload
109
+ when Message::SSH_MSG_CHANNEL_DATA::VALUE
110
+ channel_data payload
111
+ when Message::SSH_MSG_CHANNEL_EXTENDED_DATA::VALUE
112
+ channel_extended_data payload
113
+ when Message::SSH_MSG_CHANNEL_EOF::VALUE
114
+ channel_eof payload
115
+ when Message::SSH_MSG_CHANNEL_CLOSE::VALUE
116
+ channel_close payload
117
+ else
118
+ @logger.warn { "received unsupported message: id: #{payload[0,1].unpack("C")[0]}" }
119
+ end
120
+ end
121
+ rescue => e
122
+ @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
123
+ ensure
77
124
  @logger.info { "closing connection loop" }
78
- break
79
- end
80
- @username ||= @authentication.username
81
- @variables ||= @authentication.variables
82
- case payload[0,1].unpack("C")[0]
83
- when Message::SSH_MSG_GLOBAL_REQUEST::VALUE
84
- global_request payload
85
- when Message::SSH_MSG_CHANNEL_OPEN::VALUE
86
- channel_open payload
87
- when Message::SSH_MSG_CHANNEL_OPEN_CONFIRMATION::VALUE
88
- channel_open_confirmation payload
89
- when Message::SSH_MSG_CHANNEL_REQUEST::VALUE
90
- channel_request payload
91
- when Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE
92
- channel_window_adjust payload
93
- when Message::SSH_MSG_CHANNEL_DATA::VALUE
94
- channel_data payload
95
- when Message::SSH_MSG_CHANNEL_EOF::VALUE
96
- channel_eof payload
97
- when Message::SSH_MSG_CHANNEL_CLOSE::VALUE
98
- channel_close payload
99
- else
100
- @logger.warn { "received unsupported message: id: #{payload[0,1].unpack("C")[0]}" }
125
+ close
126
+ @logger.info { "connection loop closed" }
101
127
  end
102
128
  end
103
- @logger.info { "closing connection" }
104
- close
105
- @logger.info { "connection closed" }
106
129
  end
107
130
 
108
131
  def global_request payload
@@ -149,11 +172,40 @@ module HrrRbSsh
149
172
  channel.start
150
173
  send_channel_open_confirmation channel
151
174
  rescue => e
175
+ @logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
152
176
  recipient_channel = message[:'sender channel']
153
177
  send_channel_open_failure recipient_channel, Message::SSH_MSG_CHANNEL_OPEN_FAILURE::ReasonCode::SSH_OPEN_CONNECT_FAILED, e.message
154
178
  end
155
179
  end
156
180
 
181
+ def request_channel_open channel_type, channel_specific_message={}, wait_response=true
182
+ @logger.info { 'request channel open' }
183
+ case channel_type
184
+ when "session"
185
+ channel = Channel.new self, {:'channel type' => channel_type}
186
+ @channels[channel.local_channel] = channel
187
+ end
188
+ message = {
189
+ :'message number' => Message::SSH_MSG_CHANNEL_OPEN::VALUE,
190
+ :'channel type' => channel_type,
191
+ :'sender channel' => channel.local_channel,
192
+ :'initial window size' => channel.local_window_size,
193
+ :'maximum packet size' => channel.local_maximum_packet_size,
194
+ }
195
+ send_channel_open message.merge(channel_specific_message)
196
+ @logger.info { 'sent channel open' }
197
+ if wait_response
198
+ @logger.info { 'wait response' }
199
+ channel.wait_until_started
200
+ end
201
+ unless channel.closed?
202
+ @logger.info { 'channel opened' }
203
+ channel
204
+ else
205
+ raise "Faild opening channel"
206
+ end
207
+ end
208
+
157
209
  def channel_open_confirmation payload
158
210
  @logger.info { 'received ' + Message::SSH_MSG_CHANNEL_OPEN_CONFIRMATION::ID }
159
211
  message = Message::SSH_MSG_CHANNEL_OPEN_CONFIRMATION.decode payload
@@ -183,12 +235,18 @@ module HrrRbSsh
183
235
  @channels[local_channel].receive_message_queue.enq message
184
236
  end
185
237
 
238
+ def channel_extended_data payload
239
+ @logger.info { 'received ' + Message::SSH_MSG_CHANNEL_EXTENDED_DATA::ID }
240
+ message = Message::SSH_MSG_CHANNEL_EXTENDED_DATA.decode payload
241
+ local_channel = message[:'recipient channel']
242
+ @channels[local_channel].receive_message_queue.enq message
243
+ end
244
+
186
245
  def channel_eof payload
187
246
  @logger.info { 'received ' + Message::SSH_MSG_CHANNEL_EOF::ID }
188
247
  message = Message::SSH_MSG_CHANNEL_EOF.decode payload
189
248
  local_channel = message[:'recipient channel']
190
- channel = @channels[local_channel]
191
- channel.receive_message_queue.close
249
+ @channels[local_channel].receive_message_queue.enq message
192
250
  end
193
251
 
194
252
  def channel_close payload
@@ -197,6 +255,9 @@ module HrrRbSsh
197
255
  local_channel = message[:'recipient channel']
198
256
  channel = @channels[local_channel]
199
257
  channel.close
258
+ @logger.info { "wait until threads closed in channel" }
259
+ channel.wait_until_closed
260
+ @logger.info { "channel closed" }
200
261
  @logger.info { "deleting channel" }
201
262
  @channels.delete local_channel
202
263
  @logger.info { "channel deleted" }
@@ -25,31 +25,31 @@ module HrrRbSsh
25
25
 
26
26
  def fatal
27
27
  if @@logger
28
- @@logger.fatal { "#{@name}: #{yield}" }
28
+ @@logger.fatal { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
29
29
  end
30
30
  end
31
31
 
32
32
  def error
33
33
  if @@logger
34
- @@logger.error { "#{@name}: #{yield}" }
34
+ @@logger.error { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
35
35
  end
36
36
  end
37
37
 
38
38
  def warn
39
39
  if @@logger
40
- @@logger.warn { "#{@name}: #{yield}" }
40
+ @@logger.warn { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
41
41
  end
42
42
  end
43
43
 
44
44
  def info
45
45
  if @@logger
46
- @@logger.info { "#{@name}: #{yield}" }
46
+ @@logger.info { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
47
47
  end
48
48
  end
49
49
 
50
50
  def debug
51
51
  if @@logger
52
- @@logger.debug { "#{@name}: #{yield}" }
52
+ @@logger.debug { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
53
53
  end
54
54
  end
55
55
  end
@@ -20,9 +20,9 @@ module HrrRbSsh
20
20
 
21
21
  def start io
22
22
  @logger.info { "start server service" }
23
- transport = HrrRbSsh::Transport.new io, HrrRbSsh::Mode::SERVER, @options
24
- authentication = HrrRbSsh::Authentication.new transport, @options
25
- connection = HrrRbSsh::Connection.new authentication, @options
23
+ transport = Transport.new io, Mode::SERVER, @options
24
+ authentication = Authentication.new transport, Mode::SERVER, @options
25
+ connection = Connection.new authentication, Mode::SERVER, @options
26
26
  connection.start
27
27
  end
28
28
  end
@@ -22,74 +22,79 @@ module HrrRbSsh
22
22
  @dh.g = OpenSSL::BN.new(self.class::G)
23
23
  end
24
24
  @dh.generate_key!
25
+ @public_key = @dh.pub_key.to_i
25
26
  end
26
27
 
27
- def start transport, mode
28
- case mode
28
+ def start transport
29
+ case transport.mode
29
30
  when Mode::SERVER
30
- receive_kexdh_init transport.receive
31
+ @k_s = transport.server_host_key_algorithm.server_public_host_key
32
+ @f = @public_key
33
+ message = receive_kexdh_init transport.receive
34
+ @e = message[:'e']
35
+ @shared_secret = OpenSSL::BN.new(@dh.compute_key(OpenSSL::BN.new(@e)), 2).to_i
31
36
  send_kexdh_reply transport
32
- else
33
- raise "unsupported mode"
37
+ when Mode::CLIENT
38
+ @e = @public_key
39
+ send_kexdh_init transport
40
+ message = receive_kexdh_reply transport.receive
41
+ @k_s = message[:'server public host key and certificates (K_S)']
42
+ @f = message[:'f']
43
+ @shared_secret = OpenSSL::BN.new(@dh.compute_key(OpenSSL::BN.new(@f)), 2).to_i
34
44
  end
35
45
  end
36
46
 
37
- def set_e e
38
- @e = e
39
- end
40
-
41
47
  def shared_secret
42
- k = OpenSSL::BN.new(@dh.compute_key(OpenSSL::BN.new(@e)), 2).to_i
43
- end
44
-
45
- def pub_key
46
- f = @dh.pub_key.to_i
48
+ @shared_secret
47
49
  end
48
50
 
49
51
  def hash transport
50
- e = @e
51
- k = shared_secret
52
- f = pub_key
53
-
54
52
  h0_payload = {
55
53
  :'V_C' => transport.v_c,
56
54
  :'V_S' => transport.v_s,
57
55
  :'I_C' => transport.i_c,
58
56
  :'I_S' => transport.i_s,
59
- :'K_S' => transport.server_host_key_algorithm.server_public_host_key,
60
- :'e' => e,
61
- :'f' => f,
62
- :'k' => k,
57
+ :'K_S' => @k_s,
58
+ :'e' => @e,
59
+ :'f' => @f,
60
+ :'k' => @shared_secret,
63
61
  }
64
62
  h0 = H0.encode h0_payload
65
-
66
- h = OpenSSL::Digest.digest self.class::DIGEST, h0
67
-
68
- h
63
+ h = OpenSSL::Digest.digest self.class::DIGEST, h0
69
64
  end
70
65
 
71
66
  def sign transport
72
67
  h = hash transport
73
68
  s = transport.server_host_key_algorithm.sign h
74
-
75
- s
76
69
  end
77
70
 
78
71
  def receive_kexdh_init payload
79
- message = Message::SSH_MSG_KEXDH_INIT.decode payload
80
- set_e message[:'e']
72
+ Message::SSH_MSG_KEXDH_INIT.decode payload
81
73
  end
82
74
 
83
75
  def send_kexdh_reply transport
84
76
  message = {
85
77
  :'message number' => Message::SSH_MSG_KEXDH_REPLY::VALUE,
86
- :'server public host key and certificates (K_S)' => transport.server_host_key_algorithm.server_public_host_key,
87
- :'f' => pub_key,
78
+ :'server public host key and certificates (K_S)' => @k_s,
79
+ :'f' => @f,
88
80
  :'signature of H' => sign(transport),
89
81
  }
90
82
  payload = Message::SSH_MSG_KEXDH_REPLY.encode message
91
83
  transport.send payload
92
84
  end
85
+
86
+ def send_kexdh_init transport
87
+ message = {
88
+ :'message number' => Message::SSH_MSG_KEXDH_INIT::VALUE,
89
+ :'e' => @e,
90
+ }
91
+ payload = Message::SSH_MSG_KEXDH_INIT.encode message
92
+ transport.send payload
93
+ end
94
+
95
+ def receive_kexdh_reply payload
96
+ Message::SSH_MSG_KEXDH_REPLY.decode payload
97
+ end
93
98
  end
94
99
  end
95
100
  end
@@ -16,25 +16,50 @@ module HrrRbSsh
16
16
  @logger = Logger.new(self.class.name)
17
17
  end
18
18
 
19
- def start transport, mode
20
- case mode
19
+ def start transport
20
+ case transport.mode
21
21
  when Mode::SERVER
22
- receive_kex_dh_gex_request transport.receive
23
- set_dh
22
+ message = receive_kex_dh_gex_request transport.receive
23
+ @min = message[:'min']
24
+ @n = message[:'n']
25
+ @max = message[:'max']
26
+ initialize_dh
27
+ @p = @dh.p.to_i
28
+ @g = @dh.g.to_i
24
29
  send_kex_dh_gex_group transport
25
- receive_kex_dh_gex_init transport.receive
30
+ @k_s = transport.server_host_key_algorithm.server_public_host_key
31
+ @f = @public_key
32
+ message = receive_kex_dh_gex_init transport.receive
33
+ @e = message[:'e']
34
+ @shared_secret = OpenSSL::BN.new(@dh.compute_key(OpenSSL::BN.new(@e)), 2).to_i
26
35
  send_kex_dh_gex_reply transport
27
- else
28
- raise "unsupported mode"
36
+ when Mode::CLIENT
37
+ @min = 1024
38
+ @n = 2048
39
+ @max = 8192
40
+ send_kex_dh_gex_request transport
41
+ message = receive_kex_dh_gex_group transport.receive
42
+ @p = message[:'p']
43
+ @g = message[:'g']
44
+ initialize_dh [@p, @g]
45
+ @e = @public_key
46
+ send_kex_dh_gex_init transport
47
+ message = receive_kex_dh_gex_reply transport.receive
48
+ @k_s = message[:'server public host key and certificates (K_S)']
49
+ @f = message[:'f']
50
+ @shared_secret = OpenSSL::BN.new(@dh.compute_key(OpenSSL::BN.new(@f)), 2).to_i
29
51
  end
30
52
  end
31
53
 
32
- def set_dh
33
- p_list = KexAlgorithm.list_supported.map{ |e| KexAlgorithm[e] }.select{ |e| e.const_defined?(:P) }.map{ |e| [OpenSSL::BN.new(e::P,16).num_bits, e::P] }.sort_by{ |e| e[0] }.reverse
34
- candidate = p_list.find{ |e| e[0] <= @n }
35
- raise unless (@min .. @max).include?(candidate[0])
36
- p = candidate[1]
37
- g = 2
54
+ def initialize_dh pg=nil
55
+ unless pg
56
+ p_list = KexAlgorithm.list_supported.map{ |e| KexAlgorithm[e] }.select{ |e| e.const_defined?(:P) }.map{ |e| [OpenSSL::BN.new(e::P,16).num_bits, e::P] }.sort_by{ |e| e[0] }.reverse
57
+ candidate = p_list.find{ |e| e[0] <= @n }
58
+ raise unless (@min .. @max).include?(candidate[0])
59
+ p, g = candidate[1], 2
60
+ else
61
+ p, g = pg
62
+ end
38
63
  @dh = OpenSSL::PKey::DH.new
39
64
  if @dh.respond_to?(:set_pqg)
40
65
  @dh.set_pqg OpenSSL::BN.new(p, 16), nil, OpenSSL::BN.new(g)
@@ -43,85 +68,94 @@ module HrrRbSsh
43
68
  @dh.g = OpenSSL::BN.new(g)
44
69
  end
45
70
  @dh.generate_key!
46
- end
47
-
48
- def set_e e
49
- @e = e
71
+ @public_key = @dh.pub_key.to_i
50
72
  end
51
73
 
52
74
  def shared_secret
53
- k = OpenSSL::BN.new(@dh.compute_key(OpenSSL::BN.new(@e)), 2).to_i
54
- end
55
-
56
- def pub_key
57
- f = @dh.pub_key.to_i
75
+ @shared_secret
58
76
  end
59
77
 
60
78
  def hash transport
61
- e = @e
62
- k = shared_secret
63
- f = pub_key
64
-
65
79
  h0_payload = {
66
80
  :'V_C' => transport.v_c,
67
81
  :'V_S' => transport.v_s,
68
82
  :'I_C' => transport.i_c,
69
83
  :'I_S' => transport.i_s,
70
- :'K_S' => transport.server_host_key_algorithm.server_public_host_key,
84
+ :'K_S' => @k_s,
71
85
  :'min' => @min,
72
86
  :'n' => @n,
73
87
  :'max' => @max,
74
- :'p' => @dh.p.to_i,
75
- :'g' => @dh.g.to_i,
76
- :'e' => e,
77
- :'f' => f,
78
- :'k' => k,
88
+ :'p' => @p,
89
+ :'g' => @g,
90
+ :'e' => @e,
91
+ :'f' => @f,
92
+ :'k' => @shared_secret,
79
93
  }
80
94
  h0 = H0.encode h0_payload
81
-
82
95
  h = OpenSSL::Digest.digest self.class::DIGEST, h0
83
-
84
- h
85
96
  end
86
97
 
87
98
  def sign transport
88
99
  h = hash transport
89
100
  s = transport.server_host_key_algorithm.sign h
90
- s
91
101
  end
92
102
 
93
103
  def receive_kex_dh_gex_request payload
94
- message = Message::SSH_MSG_KEX_DH_GEX_REQUEST.decode payload
95
- @min = message[:'min']
96
- @n = message[:'n']
97
- @max = message[:'max']
104
+ Message::SSH_MSG_KEX_DH_GEX_REQUEST.decode payload
98
105
  end
99
106
 
100
107
  def send_kex_dh_gex_group transport
101
108
  message = {
102
109
  :'message number' => Message::SSH_MSG_KEX_DH_GEX_GROUP::VALUE,
103
- :'p' => @dh.p.to_i,
104
- :'g' => @dh.g.to_i,
110
+ :'p' => @p,
111
+ :'g' => @g,
105
112
  }
106
113
  payload = Message::SSH_MSG_KEX_DH_GEX_GROUP.encode message
107
114
  transport.send payload
108
115
  end
109
116
 
110
117
  def receive_kex_dh_gex_init payload
111
- message = Message::SSH_MSG_KEX_DH_GEX_INIT.decode payload
112
- set_e message[:'e']
118
+ Message::SSH_MSG_KEX_DH_GEX_INIT.decode payload
113
119
  end
114
120
 
115
121
  def send_kex_dh_gex_reply transport
116
122
  message = {
117
123
  :'message number' => Message::SSH_MSG_KEX_DH_GEX_REPLY::VALUE,
118
- :'server public host key and certificates (K_S)' => transport.server_host_key_algorithm.server_public_host_key,
119
- :'f' => pub_key,
124
+ :'server public host key and certificates (K_S)' => @k_s,
125
+ :'f' => @f,
120
126
  :'signature of H' => sign(transport),
121
127
  }
122
128
  payload = Message::SSH_MSG_KEX_DH_GEX_REPLY.encode message
123
129
  transport.send payload
124
130
  end
131
+
132
+ def send_kex_dh_gex_request transport
133
+ message = {
134
+ :'message number' => Message::SSH_MSG_KEX_DH_GEX_REQUEST::VALUE,
135
+ :'min' => @min,
136
+ :'n' => @n,
137
+ :'max' => @max,
138
+ }
139
+ payload = Message::SSH_MSG_KEX_DH_GEX_REQUEST.encode message
140
+ transport.send payload
141
+ end
142
+
143
+ def receive_kex_dh_gex_group payload
144
+ Message::SSH_MSG_KEX_DH_GEX_GROUP.decode payload
145
+ end
146
+
147
+ def send_kex_dh_gex_init transport
148
+ message = {
149
+ :'message number' => Message::SSH_MSG_KEX_DH_GEX_INIT::VALUE,
150
+ :'e' => @e,
151
+ }
152
+ payload = Message::SSH_MSG_KEX_DH_GEX_INIT.encode message
153
+ transport.send payload
154
+ end
155
+
156
+ def receive_kex_dh_gex_reply payload
157
+ Message::SSH_MSG_KEX_DH_GEX_REPLY.decode payload
158
+ end
125
159
  end
126
160
  end
127
161
  end
@@ -16,74 +16,79 @@ module HrrRbSsh
16
16
  @logger = Logger.new(self.class.name)
17
17
  @dh = OpenSSL::PKey::EC.new(self.class::CURVE_NAME)
18
18
  @dh.generate_key
19
+ @public_key = @dh.public_key.to_bn.to_i
19
20
  end
20
21
 
21
- def start transport, mode
22
- case mode
22
+ def start transport
23
+ case transport.mode
23
24
  when Mode::SERVER
24
- receive_kexecdh_init transport.receive
25
+ @k_s = transport.server_host_key_algorithm.server_public_host_key
26
+ @q_s = @public_key
27
+ message = receive_kexecdh_init transport.receive
28
+ @q_c = message[:'Q_C']
29
+ @shared_secret = OpenSSL::BN.new(@dh.dh_compute_key(OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(self.class::CURVE_NAME).group, OpenSSL::BN.new(@q_c))), 2).to_i
25
30
  send_kexecdh_reply transport
26
- else
27
- raise "unsupported mode"
31
+ when Mode::CLIENT
32
+ @q_c = @public_key
33
+ send_kexecdh_init transport
34
+ message = receive_kexecdh_reply transport.receive
35
+ @k_s = message[:'K_S']
36
+ @q_s = message[:'Q_S']
37
+ @shared_secret = OpenSSL::BN.new(@dh.dh_compute_key(OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(self.class::CURVE_NAME).group, OpenSSL::BN.new(@q_s))), 2).to_i
28
38
  end
29
39
  end
30
40
 
31
- def set_q_c q_c
32
- @q_c = q_c
33
- end
34
-
35
41
  def shared_secret
36
- k = OpenSSL::BN.new(@dh.dh_compute_key(OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(self.class::CURVE_NAME).group, OpenSSL::BN.new(@q_c))), 2).to_i
37
- end
38
-
39
- def public_key
40
- f = @dh.public_key.to_bn.to_i
42
+ @shared_secret
41
43
  end
42
44
 
43
45
  def hash transport
44
- q_c = @q_c
45
- q_s = public_key
46
- k = shared_secret
47
-
48
46
  h0_payload = {
49
47
  :'V_C' => transport.v_c,
50
48
  :'V_S' => transport.v_s,
51
49
  :'I_C' => transport.i_c,
52
50
  :'I_S' => transport.i_s,
53
- :'K_S' => transport.server_host_key_algorithm.server_public_host_key,
54
- :'Q_C' => q_c,
55
- :'Q_S' => q_s,
56
- :'K' => k,
51
+ :'K_S' => @k_s,
52
+ :'Q_C' => @q_c,
53
+ :'Q_S' => @q_s,
54
+ :'K' => @shared_secret,
57
55
  }
58
56
  h0 = H0.encode h0_payload
59
-
60
- h = OpenSSL::Digest.digest self.class::DIGEST, h0
61
-
62
- h
57
+ h = OpenSSL::Digest.digest self.class::DIGEST, h0
63
58
  end
64
59
 
65
60
  def sign transport
66
61
  h = hash transport
67
62
  s = transport.server_host_key_algorithm.sign h
68
-
69
- s
70
63
  end
71
64
 
72
65
  def receive_kexecdh_init payload
73
- message = Message::SSH_MSG_KEXECDH_INIT.decode payload
74
- set_q_c message[:'Q_C']
66
+ Message::SSH_MSG_KEXECDH_INIT.decode payload
75
67
  end
76
68
 
77
69
  def send_kexecdh_reply transport
78
70
  message = {
79
71
  :'message number' => Message::SSH_MSG_KEXECDH_REPLY::VALUE,
80
- :'K_S' => transport.server_host_key_algorithm.server_public_host_key,
81
- :'Q_S' => public_key,
72
+ :'K_S' => @k_s,
73
+ :'Q_S' => @q_s,
82
74
  :'signature of H' => sign(transport),
83
75
  }
84
76
  payload = Message::SSH_MSG_KEXECDH_REPLY.encode message
85
77
  transport.send payload
86
78
  end
79
+
80
+ def send_kexecdh_init transport
81
+ message = {
82
+ :'message number' => Message::SSH_MSG_KEXECDH_INIT::VALUE,
83
+ :'Q_C' => @q_c,
84
+ }
85
+ payload = Message::SSH_MSG_KEXECDH_INIT.encode message
86
+ transport.send payload
87
+ end
88
+
89
+ def receive_kexecdh_reply payload
90
+ Message::SSH_MSG_KEXECDH_REPLY.decode payload
91
+ end
87
92
  end
88
93
  end
89
94
  end