github.com/inflatablewoman/deis@v1.0.1-0.20141111034523-a4511c46a6ce/deisctl/Godeps/_workspace/src/code.google.com/p/go.crypto/ssh/kex.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssh 6 7 import ( 8 "crypto" 9 "crypto/ecdsa" 10 "crypto/elliptic" 11 "crypto/rand" 12 "errors" 13 "io" 14 "math/big" 15 ) 16 17 const ( 18 kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" 19 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" 20 kexAlgoECDH256 = "ecdh-sha2-nistp256" 21 kexAlgoECDH384 = "ecdh-sha2-nistp384" 22 kexAlgoECDH521 = "ecdh-sha2-nistp521" 23 ) 24 25 // kexResult captures the outcome of a key exchange. 26 type kexResult struct { 27 // Session hash. See also RFC 4253, section 8. 28 H []byte 29 30 // Shared secret. See also RFC 4253, section 8. 31 K []byte 32 33 // Host key as hashed into H. 34 HostKey []byte 35 36 // Signature of H. 37 Signature []byte 38 39 // A cryptographic hash function that matches the security 40 // level of the key exchange algorithm. It is used for 41 // calculating H, and for deriving keys from H and K. 42 Hash crypto.Hash 43 44 // The session ID, which is the first H computed. This is used 45 // to signal data inside transport. 46 SessionID []byte 47 } 48 49 // handshakeMagics contains data that is always included in the 50 // session hash. 51 type handshakeMagics struct { 52 clientVersion, serverVersion []byte 53 clientKexInit, serverKexInit []byte 54 } 55 56 func (m *handshakeMagics) write(w io.Writer) { 57 writeString(w, m.clientVersion) 58 writeString(w, m.serverVersion) 59 writeString(w, m.clientKexInit) 60 writeString(w, m.serverKexInit) 61 } 62 63 // kexAlgorithm abstracts different key exchange algorithms. 64 type kexAlgorithm interface { 65 // Server runs server-side key agreement, signing the result 66 // with a hostkey. 67 Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) 68 69 // Client runs the client-side key agreement. Caller is 70 // responsible for verifying the host key signature. 71 Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) 72 } 73 74 // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. 75 type dhGroup struct { 76 g, p *big.Int 77 } 78 79 func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { 80 if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 { 81 return nil, errors.New("ssh: DH parameter out of bounds") 82 } 83 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil 84 } 85 86 func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 87 hashFunc := crypto.SHA1 88 89 x, err := rand.Int(randSource, group.p) 90 if err != nil { 91 return nil, err 92 } 93 X := new(big.Int).Exp(group.g, x, group.p) 94 kexDHInit := kexDHInitMsg{ 95 X: X, 96 } 97 if err := c.writePacket(Marshal(&kexDHInit)); err != nil { 98 return nil, err 99 } 100 101 packet, err := c.readPacket() 102 if err != nil { 103 return nil, err 104 } 105 106 var kexDHReply kexDHReplyMsg 107 if err = Unmarshal(packet, &kexDHReply); err != nil { 108 return nil, err 109 } 110 111 kInt, err := group.diffieHellman(kexDHReply.Y, x) 112 if err != nil { 113 return nil, err 114 } 115 116 h := hashFunc.New() 117 magics.write(h) 118 writeString(h, kexDHReply.HostKey) 119 writeInt(h, X) 120 writeInt(h, kexDHReply.Y) 121 K := make([]byte, intLength(kInt)) 122 marshalInt(K, kInt) 123 h.Write(K) 124 125 return &kexResult{ 126 H: h.Sum(nil), 127 K: K, 128 HostKey: kexDHReply.HostKey, 129 Signature: kexDHReply.Signature, 130 Hash: crypto.SHA1, 131 }, nil 132 } 133 134 func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 135 hashFunc := crypto.SHA1 136 packet, err := c.readPacket() 137 if err != nil { 138 return 139 } 140 var kexDHInit kexDHInitMsg 141 if err = Unmarshal(packet, &kexDHInit); err != nil { 142 return 143 } 144 145 y, err := rand.Int(randSource, group.p) 146 if err != nil { 147 return 148 } 149 150 Y := new(big.Int).Exp(group.g, y, group.p) 151 kInt, err := group.diffieHellman(kexDHInit.X, y) 152 if err != nil { 153 return nil, err 154 } 155 156 hostKeyBytes := priv.PublicKey().Marshal() 157 158 h := hashFunc.New() 159 magics.write(h) 160 writeString(h, hostKeyBytes) 161 writeInt(h, kexDHInit.X) 162 writeInt(h, Y) 163 164 K := make([]byte, intLength(kInt)) 165 marshalInt(K, kInt) 166 h.Write(K) 167 168 H := h.Sum(nil) 169 170 // H is already a hash, but the hostkey signing will apply its 171 // own key-specific hash algorithm. 172 sig, err := signAndMarshal(priv, randSource, H) 173 if err != nil { 174 return nil, err 175 } 176 177 kexDHReply := kexDHReplyMsg{ 178 HostKey: hostKeyBytes, 179 Y: Y, 180 Signature: sig, 181 } 182 packet = Marshal(&kexDHReply) 183 184 err = c.writePacket(packet) 185 return &kexResult{ 186 H: H, 187 K: K, 188 HostKey: hostKeyBytes, 189 Signature: sig, 190 Hash: crypto.SHA1, 191 }, nil 192 } 193 194 // ecdh performs Elliptic Curve Diffie-Hellman key exchange as 195 // described in RFC 5656, section 4. 196 type ecdh struct { 197 curve elliptic.Curve 198 } 199 200 func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 201 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 202 if err != nil { 203 return nil, err 204 } 205 206 kexInit := kexECDHInitMsg{ 207 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), 208 } 209 210 serialized := Marshal(&kexInit) 211 if err := c.writePacket(serialized); err != nil { 212 return nil, err 213 } 214 215 packet, err := c.readPacket() 216 if err != nil { 217 return nil, err 218 } 219 220 var reply kexECDHReplyMsg 221 if err = Unmarshal(packet, &reply); err != nil { 222 return nil, err 223 } 224 225 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) 226 if err != nil { 227 return nil, err 228 } 229 230 // generate shared secret 231 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) 232 233 h := ecHash(kex.curve).New() 234 magics.write(h) 235 writeString(h, reply.HostKey) 236 writeString(h, kexInit.ClientPubKey) 237 writeString(h, reply.EphemeralPubKey) 238 K := make([]byte, intLength(secret)) 239 marshalInt(K, secret) 240 h.Write(K) 241 242 return &kexResult{ 243 H: h.Sum(nil), 244 K: K, 245 HostKey: reply.HostKey, 246 Signature: reply.Signature, 247 Hash: ecHash(kex.curve), 248 }, nil 249 } 250 251 // unmarshalECKey parses and checks an EC key. 252 func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { 253 x, y = elliptic.Unmarshal(curve, pubkey) 254 if x == nil { 255 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") 256 } 257 if !validateECPublicKey(curve, x, y) { 258 return nil, nil, errors.New("ssh: public key not on curve") 259 } 260 return x, y, nil 261 } 262 263 // validateECPublicKey checks that the point is a valid public key for 264 // the given curve. See [SEC1], 3.2.2 265 func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { 266 if x.Sign() == 0 && y.Sign() == 0 { 267 return false 268 } 269 270 if x.Cmp(curve.Params().P) >= 0 { 271 return false 272 } 273 274 if y.Cmp(curve.Params().P) >= 0 { 275 return false 276 } 277 278 if !curve.IsOnCurve(x, y) { 279 return false 280 } 281 282 // We don't check if N * PubKey == 0, since 283 // 284 // - the NIST curves have cofactor = 1, so this is implicit. 285 // (We don't foresee an implementation that supports non NIST 286 // curves) 287 // 288 // - for ephemeral keys, we don't need to worry about small 289 // subgroup attacks. 290 return true 291 } 292 293 func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 294 packet, err := c.readPacket() 295 if err != nil { 296 return nil, err 297 } 298 299 var kexECDHInit kexECDHInitMsg 300 if err = Unmarshal(packet, &kexECDHInit); err != nil { 301 return nil, err 302 } 303 304 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) 305 if err != nil { 306 return nil, err 307 } 308 309 // We could cache this key across multiple users/multiple 310 // connection attempts, but the benefit is small. OpenSSH 311 // generates a new key for each incoming connection. 312 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 313 if err != nil { 314 return nil, err 315 } 316 317 hostKeyBytes := priv.PublicKey().Marshal() 318 319 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) 320 321 // generate shared secret 322 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) 323 324 h := ecHash(kex.curve).New() 325 magics.write(h) 326 writeString(h, hostKeyBytes) 327 writeString(h, kexECDHInit.ClientPubKey) 328 writeString(h, serializedEphKey) 329 330 K := make([]byte, intLength(secret)) 331 marshalInt(K, secret) 332 h.Write(K) 333 334 H := h.Sum(nil) 335 336 // H is already a hash, but the hostkey signing will apply its 337 // own key-specific hash algorithm. 338 sig, err := signAndMarshal(priv, rand, H) 339 if err != nil { 340 return nil, err 341 } 342 343 reply := kexECDHReplyMsg{ 344 EphemeralPubKey: serializedEphKey, 345 HostKey: hostKeyBytes, 346 Signature: sig, 347 } 348 349 serialized := Marshal(&reply) 350 if err := c.writePacket(serialized); err != nil { 351 return nil, err 352 } 353 354 return &kexResult{ 355 H: H, 356 K: K, 357 HostKey: reply.HostKey, 358 Signature: sig, 359 Hash: ecHash(kex.curve), 360 }, nil 361 } 362 363 var kexAlgoMap = map[string]kexAlgorithm{} 364 365 func init() { 366 // This is the group called diffie-hellman-group1-sha1 in RFC 367 // 4253 and Oakley Group 2 in RFC 2409. 368 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) 369 kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ 370 g: new(big.Int).SetInt64(2), 371 p: p, 372 } 373 374 // This is the group called diffie-hellman-group14-sha1 in RFC 375 // 4253 and Oakley Group 14 in RFC 3526. 376 p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) 377 378 kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ 379 g: new(big.Int).SetInt64(2), 380 p: p, 381 } 382 383 kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} 384 kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} 385 kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} 386 }