1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 Variant on L{KexGroup1 <ssh.kex_group1.KexGroup1>} where the prime "p" and
21 generator "g" are provided by the server. A bit more work is required on the
22 client side, and a B{lot} more on the server side.
23 """
24
25 from Crypto.Hash import SHA
26 from Crypto.Util import number
27
28 from ssh.common import *
29 from ssh import util
30 from ssh.message import Message
31 from ssh.ssh_exception import SSHException
32
33
34 _MSG_KEXDH_GEX_REQUEST_OLD, _MSG_KEXDH_GEX_GROUP, _MSG_KEXDH_GEX_INIT, \
35 _MSG_KEXDH_GEX_REPLY, _MSG_KEXDH_GEX_REQUEST = range(30, 35)
36
37
39
40 name = 'diffie-hellman-group-exchange-sha1'
41 min_bits = 1024
42 max_bits = 8192
43 preferred_bits = 2048
44
46 self.transport = transport
47 self.p = None
48 self.q = None
49 self.g = None
50 self.x = None
51 self.e = None
52 self.f = None
53 self.old_style = False
54
75
77 if ptype == _MSG_KEXDH_GEX_REQUEST:
78 return self._parse_kexdh_gex_request(m)
79 elif ptype == _MSG_KEXDH_GEX_GROUP:
80 return self._parse_kexdh_gex_group(m)
81 elif ptype == _MSG_KEXDH_GEX_INIT:
82 return self._parse_kexdh_gex_init(m)
83 elif ptype == _MSG_KEXDH_GEX_REPLY:
84 return self._parse_kexdh_gex_reply(m)
85 elif ptype == _MSG_KEXDH_GEX_REQUEST_OLD:
86 return self._parse_kexdh_gex_request_old(m)
87 raise SSHException('KexGex asked to handle packet type %d' % ptype)
88
89
90
91
92
94
95 q = (self.p - 1) // 2
96 qnorm = util.deflate_long(q, 0)
97 qhbyte = ord(qnorm[0])
98 bytes = len(qnorm)
99 qmask = 0xff
100 while not (qhbyte & 0x80):
101 qhbyte <<= 1
102 qmask >>= 1
103 while True:
104 x_bytes = self.transport.rng.read(bytes)
105 x_bytes = chr(ord(x_bytes[0]) & qmask) + x_bytes[1:]
106 x = util.inflate_long(x_bytes, 1)
107 if (x > 1) and (x < q):
108 break
109 self.x = x
110
112 minbits = m.get_int()
113 preferredbits = m.get_int()
114 maxbits = m.get_int()
115
116 if preferredbits > self.max_bits:
117 preferredbits = self.max_bits
118 if preferredbits < self.min_bits:
119 preferredbits = self.min_bits
120
121
122
123 if minbits > preferredbits:
124 minbits = preferredbits
125 if maxbits < preferredbits:
126 maxbits = preferredbits
127
128 self.min_bits = minbits
129 self.preferred_bits = preferredbits
130 self.max_bits = maxbits
131
132 pack = self.transport._get_modulus_pack()
133 if pack is None:
134 raise SSHException('Can\'t do server-side gex with no modulus pack')
135 self.transport._log(DEBUG, 'Picking p (%d <= %d <= %d bits)' % (minbits, preferredbits, maxbits))
136 self.g, self.p = pack.get_modulus(minbits, preferredbits, maxbits)
137 m = Message()
138 m.add_byte(chr(_MSG_KEXDH_GEX_GROUP))
139 m.add_mpint(self.p)
140 m.add_mpint(self.g)
141 self.transport._send_message(m)
142 self.transport._expect_packet(_MSG_KEXDH_GEX_INIT)
143
165
167 self.p = m.get_mpint()
168 self.g = m.get_mpint()
169
170 bitlen = util.bit_length(self.p)
171 if (bitlen < 1024) or (bitlen > 8192):
172 raise SSHException('Server-generated gex p (don\'t ask) is out of range (%d bits)' % bitlen)
173 self.transport._log(DEBUG, 'Got server p (%d bits)' % bitlen)
174 self._generate_x()
175
176 self.e = pow(self.g, self.x, self.p)
177 m = Message()
178 m.add_byte(chr(_MSG_KEXDH_GEX_INIT))
179 m.add_mpint(self.e)
180 self.transport._send_message(m)
181 self.transport._expect_packet(_MSG_KEXDH_GEX_REPLY)
182
184 self.e = m.get_mpint()
185 if (self.e < 1) or (self.e > self.p - 1):
186 raise SSHException('Client kex "e" is out of range')
187 self._generate_x()
188 self.f = pow(self.g, self.x, self.p)
189 K = pow(self.e, self.x, self.p)
190 key = str(self.transport.get_server_key())
191
192 hm = Message()
193 hm.add(self.transport.remote_version, self.transport.local_version,
194 self.transport.remote_kex_init, self.transport.local_kex_init,
195 key)
196 if not self.old_style:
197 hm.add_int(self.min_bits)
198 hm.add_int(self.preferred_bits)
199 if not self.old_style:
200 hm.add_int(self.max_bits)
201 hm.add_mpint(self.p)
202 hm.add_mpint(self.g)
203 hm.add_mpint(self.e)
204 hm.add_mpint(self.f)
205 hm.add_mpint(K)
206 H = SHA.new(str(hm)).digest()
207 self.transport._set_K_H(K, H)
208
209 sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H)
210
211 m = Message()
212 m.add_byte(chr(_MSG_KEXDH_GEX_REPLY))
213 m.add_string(key)
214 m.add_mpint(self.f)
215 m.add_string(str(sig))
216 self.transport._send_message(m)
217 self.transport._activate_outbound()
218
244