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 3739 40 name = 'diffie-hellman-group-exchange-sha1' 41 min_bits = 1024 42 max_bits = 8192 43 preferred_bits = 2048 4424546 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 = False5456 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)7577 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 9294 # 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 = x111113 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)144146 # 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 = True166168 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)183185 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()219221 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()
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 on Sun Nov 1 22:14:17 2009 | http://epydoc.sourceforge.net |