| Home | Trees | Indices | Help | 
|---|
|  | 
  1  # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com> 
  2  # 
  3  # This file is part of paramiko. 
  4  # 
  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
  6  # terms of the GNU Lesser General Public License as published by the Free 
  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
  8  # any later version. 
  9  # 
 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 13  # details. 
 14  # 
 15  # You should have received a copy of the GNU Lesser General Public License 
 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
 18   
 19  """ 
 20  Variant on L{KexGroup1 <paramiko.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 paramiko.common import * 
 29  from paramiko import util 
 30  from paramiko.message import Message 
 31  from paramiko.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   
 56          if self.transport.server_mode: 
 57              self.transport._expect_packet(_MSG_KEXDH_GEX_REQUEST, _MSG_KEXDH_GEX_REQUEST_OLD) 
 58              return 
 59          # request a bit range: we accept (min_bits) to (max_bits), but prefer 
 60          # (preferred_bits).  according to the spec, we shouldn't pull the 
 61          # minimum up above 1024. 
 62          m = Message() 
 63          if _test_old_style: 
 64              # only used for unit tests: we shouldn't ever send this 
 65              m.add_byte(chr(_MSG_KEXDH_GEX_REQUEST_OLD)) 
 66              m.add_int(self.preferred_bits) 
 67              self.old_style = True 
 68          else: 
 69              m.add_byte(chr(_MSG_KEXDH_GEX_REQUEST)) 
 70              m.add_int(self.min_bits) 
 71              m.add_int(self.preferred_bits) 
 72              m.add_int(self.max_bits) 
 73          self.transport._send_message(m) 
 74          self.transport._expect_packet(_MSG_KEXDH_GEX_GROUP) 
 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      ###  internals... 
 91   
 92       
 94          # generate an "x" (1 < x < (p-1)/2). 
 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              self.transport.randpool.stir() 
105              x_bytes = self.transport.randpool.get_bytes(bytes) 
106              x_bytes = chr(ord(x_bytes[0]) & qmask) + x_bytes[1:] 
107              x = util.inflate_long(x_bytes, 1) 
108              if (x > 1) and (x < q): 
109                  break 
110          self.x = x 
111   
113          minbits = m.get_int() 
114          preferredbits = m.get_int() 
115          maxbits = m.get_int() 
116          # smoosh the user's preferred size into our own limits 
117          if preferredbits > self.max_bits: 
118              preferredbits = self.max_bits 
119          if preferredbits < self.min_bits: 
120              preferredbits = self.min_bits 
121          # fix min/max if they're inconsistent.  technically, we could just pout 
122          # and hang up, but there's no harm in giving them the benefit of the 
123          # doubt and just picking a bitsize for them. 
124          if minbits > preferredbits: 
125              minbits = preferredbits 
126          if maxbits < preferredbits: 
127              maxbits = preferredbits 
128          # now save a copy 
129          self.min_bits = minbits 
130          self.preferred_bits = preferredbits 
131          self.max_bits = maxbits 
132          # generate prime 
133          pack = self.transport._get_modulus_pack() 
134          if pack is None: 
135              raise SSHException('Can\'t do server-side gex with no modulus pack') 
136          self.transport._log(DEBUG, 'Picking p (%d <= %d <= %d bits)' % (minbits, preferredbits, maxbits)) 
137          self.g, self.p = pack.get_modulus(minbits, preferredbits, maxbits) 
138          m = Message() 
139          m.add_byte(chr(_MSG_KEXDH_GEX_GROUP)) 
140          m.add_mpint(self.p) 
141          m.add_mpint(self.g) 
142          self.transport._send_message(m) 
143          self.transport._expect_packet(_MSG_KEXDH_GEX_INIT) 
144   
146          # same as above, but without min_bits or max_bits (used by older clients like putty) 
147          self.preferred_bits = m.get_int() 
148          # smoosh the user's preferred size into our own limits 
149          if self.preferred_bits > self.max_bits: 
150              self.preferred_bits = self.max_bits 
151          if self.preferred_bits < self.min_bits: 
152              self.preferred_bits = self.min_bits 
153          # generate prime 
154          pack = self.transport._get_modulus_pack() 
155          if pack is None: 
156              raise SSHException('Can\'t do server-side gex with no modulus pack') 
157          self.transport._log(DEBUG, 'Picking p (~ %d bits)' % (self.preferred_bits,)) 
158          self.g, self.p = pack.get_modulus(self.min_bits, self.preferred_bits, self.max_bits) 
159          m = Message() 
160          m.add_byte(chr(_MSG_KEXDH_GEX_GROUP)) 
161          m.add_mpint(self.p) 
162          m.add_mpint(self.g) 
163          self.transport._send_message(m) 
164          self.transport._expect_packet(_MSG_KEXDH_GEX_INIT) 
165          self.old_style = True 
166   
168          self.p = m.get_mpint() 
169          self.g = m.get_mpint() 
170          # reject if p's bit length < 1024 or > 8192 
171          bitlen = util.bit_length(self.p) 
172          if (bitlen < 1024) or (bitlen > 8192): 
173              raise SSHException('Server-generated gex p (don\'t ask) is out of range (%d bits)' % bitlen) 
174          self.transport._log(DEBUG, 'Got server p (%d bits)' % bitlen) 
175          self._generate_x() 
176          # now compute e = g^x mod p 
177          self.e = pow(self.g, self.x, self.p) 
178          m = Message() 
179          m.add_byte(chr(_MSG_KEXDH_GEX_INIT)) 
180          m.add_mpint(self.e) 
181          self.transport._send_message(m) 
182          self.transport._expect_packet(_MSG_KEXDH_GEX_REPLY) 
183   
185          self.e = m.get_mpint() 
186          if (self.e < 1) or (self.e > self.p - 1): 
187              raise SSHException('Client kex "e" is out of range') 
188          self._generate_x() 
189          self.f = pow(self.g, self.x, self.p) 
190          K = pow(self.e, self.x, self.p) 
191          key = str(self.transport.get_server_key()) 
192          # okay, build up the hash H of (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K) 
193          hm = Message() 
194          hm.add(self.transport.remote_version, self.transport.local_version, 
195                 self.transport.remote_kex_init, self.transport.local_kex_init, 
196                 key) 
197          if not self.old_style: 
198              hm.add_int(self.min_bits) 
199          hm.add_int(self.preferred_bits) 
200          if not self.old_style: 
201              hm.add_int(self.max_bits) 
202          hm.add_mpint(self.p) 
203          hm.add_mpint(self.g) 
204          hm.add_mpint(self.e) 
205          hm.add_mpint(self.f) 
206          hm.add_mpint(K) 
207          H = SHA.new(str(hm)).digest() 
208          self.transport._set_K_H(K, H) 
209          # sign it 
210          sig = self.transport.get_server_key().sign_ssh_data(self.transport.randpool, H) 
211          # send reply 
212          m = Message() 
213          m.add_byte(chr(_MSG_KEXDH_GEX_REPLY)) 
214          m.add_string(key) 
215          m.add_mpint(self.f) 
216          m.add_string(str(sig)) 
217          self.transport._send_message(m) 
218          self.transport._activate_outbound() 
219           
221          host_key = m.get_string() 
222          self.f = m.get_mpint() 
223          sig = m.get_string() 
224          if (self.f < 1) or (self.f > self.p - 1): 
225              raise SSHException('Server kex "f" is out of range') 
226          K = pow(self.f, self.x, self.p) 
227          # okay, build up the hash H of (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K) 
228          hm = Message() 
229          hm.add(self.transport.local_version, self.transport.remote_version, 
230                 self.transport.local_kex_init, self.transport.remote_kex_init, 
231                 host_key) 
232          if not self.old_style: 
233              hm.add_int(self.min_bits) 
234          hm.add_int(self.preferred_bits) 
235          if not self.old_style: 
236              hm.add_int(self.max_bits) 
237          hm.add_mpint(self.p) 
238          hm.add_mpint(self.g) 
239          hm.add_mpint(self.e) 
240          hm.add_mpint(self.f) 
241          hm.add_mpint(K) 
242          self.transport._set_K_H(K, SHA.new(str(hm)).digest()) 
243          self.transport._verify_key(host_key, sig) 
244          self.transport._activate_outbound() 
245   
| Home | Trees | Indices | Help | 
|---|
| Generated by Epydoc 3.0.1 on Sun Nov 1 22:14:17 2009 | http://epydoc.sourceforge.net |