1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
require 'net/ssh/transport/constants'
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
module Net
module SSH
module Transport
module Kex
# A key-exchange service implementing the "ecdh-sha2-nistp256"
# key-exchange algorithm. (defined in RFC 5656)
class EcdhSHA2NistP256 < DiffieHellmanGroup1SHA1
include Loggable
include Constants
attr_reader :ecdh
def digester
OpenSSL::Digest::SHA256
end
def curve_name
OpenSSL::PKey::EC::CurveNameAlias['nistp256']
end
def initialize(algorithms, connection, data)
@algorithms = algorithms
@connection = connection
@digester = digester
@data = data.dup
@ecdh = generate_key
@logger = @data.delete(:logger)
end
private
def get_message_types
[KEXECDH_INIT, KEXECDH_REPLY]
end
def build_signature_buffer(result)
response = Net::SSH::Buffer.new
response.write_string data[:client_version_string],
data[:server_version_string],
data[:client_algorithm_packet],
data[:server_algorithm_packet],
result[:key_blob],
ecdh.public_key.to_bn.to_s(2),
result[:server_ecdh_pubkey]
response.write_bignum result[:shared_secret]
response
end
def generate_key #:nodoc:
OpenSSL::PKey::EC.new(curve_name).generate_key
end
def send_kexinit #:nodoc:
init, reply = get_message_types
# send the KEXECDH_INIT message
## byte SSH_MSG_KEX_ECDH_INIT
## string Q_C, client's ephemeral public key octet string
buffer = Net::SSH::Buffer.from(:byte, init, :mstring, ecdh.public_key.to_bn.to_s(2))
connection.send_message(buffer)
# expect the following KEXECDH_REPLY message
## byte SSH_MSG_KEX_ECDH_REPLY
## string K_S, server's public host key
## string Q_S, server's ephemeral public key octet string
## string the signature on the exchange hash
buffer = connection.next_message
raise Net::SSH::Exception, "expected REPLY" unless buffer.type == reply
result = Hash.new
result[:key_blob] = buffer.read_string
result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
result[:server_ecdh_pubkey] = buffer.read_string
# compute shared secret from server's public key and client's private key
pk = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(curve_name).group,
OpenSSL::BN.new(result[:server_ecdh_pubkey], 2))
result[:shared_secret] = OpenSSL::BN.new(ecdh.dh_compute_key(pk), 2)
sig_buffer = Net::SSH::Buffer.new(buffer.read_string)
sig_type = sig_buffer.read_string
if sig_type != algorithms.host_key
raise Net::SSH::Exception,
"host key algorithm mismatch for signature " +
"'#{sig_type}' != '#{algorithms.host_key}'"
end
result[:server_sig] = sig_buffer.read_string
return result
end
end
end; end; end; end
|