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 5package ssh 6 7import ( 8 "crypto" 9 "crypto/ecdsa" 10 "crypto/elliptic" 11 "crypto/rand" 12 "crypto/subtle" 13 "errors" 14 "io" 15 "math/big" 16 17 "golang.org/x/crypto/curve25519" 18) 19 20const ( 21 kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" 22 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" 23 kexAlgoECDH256 = "ecdh-sha2-nistp256" 24 kexAlgoECDH384 = "ecdh-sha2-nistp384" 25 kexAlgoECDH521 = "ecdh-sha2-nistp521" 26 kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" 27) 28 29// kexResult captures the outcome of a key exchange. 30type kexResult struct { 31 // Session hash. See also RFC 4253, section 8. 32 H []byte 33 34 // Shared secret. See also RFC 4253, section 8. 35 K []byte 36 37 // Host key as hashed into H. 38 HostKey []byte 39 40 // Signature of H. 41 Signature []byte 42 43 // A cryptographic hash function that matches the security 44 // level of the key exchange algorithm. It is used for 45 // calculating H, and for deriving keys from H and K. 46 Hash crypto.Hash 47 48 // The session ID, which is the first H computed. This is used 49 // to derive key material inside the transport. 50 SessionID []byte 51} 52 53// handshakeMagics contains data that is always included in the 54// session hash. 55type handshakeMagics struct { 56 clientVersion, serverVersion []byte 57 clientKexInit, serverKexInit []byte 58} 59 60func (m *handshakeMagics) write(w io.Writer) { 61 writeString(w, m.clientVersion) 62 writeString(w, m.serverVersion) 63 writeString(w, m.clientKexInit) 64 writeString(w, m.serverKexInit) 65} 66 67// kexAlgorithm abstracts different key exchange algorithms. 68type kexAlgorithm interface { 69 // Server runs server-side key agreement, signing the result 70 // with a hostkey. 71 Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) 72 73 // Client runs the client-side key agreement. Caller is 74 // responsible for verifying the host key signature. 75 Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) 76} 77 78// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. 79type dhGroup struct { 80 g, p, pMinus1 *big.Int 81} 82 83func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { 84 if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { 85 return nil, errors.New("ssh: DH parameter out of bounds") 86 } 87 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil 88} 89 90func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 91 hashFunc := crypto.SHA1 92 93 var x *big.Int 94 for { 95 var err error 96 if x, err = rand.Int(randSource, group.pMinus1); err != nil { 97 return nil, err 98 } 99 if x.Sign() > 0 { 100 break 101 } 102 } 103 104 X := new(big.Int).Exp(group.g, x, group.p) 105 kexDHInit := kexDHInitMsg{ 106 X: X, 107 } 108 if err := c.writePacket(Marshal(&kexDHInit)); err != nil { 109 return nil, err 110 } 111 112 packet, err := c.readPacket() 113 if err != nil { 114 return nil, err 115 } 116 117 var kexDHReply kexDHReplyMsg 118 if err = Unmarshal(packet, &kexDHReply); err != nil { 119 return nil, err 120 } 121 122 ki, err := group.diffieHellman(kexDHReply.Y, x) 123 if err != nil { 124 return nil, err 125 } 126 127 h := hashFunc.New() 128 magics.write(h) 129 writeString(h, kexDHReply.HostKey) 130 writeInt(h, X) 131 writeInt(h, kexDHReply.Y) 132 K := make([]byte, intLength(ki)) 133 marshalInt(K, ki) 134 h.Write(K) 135 136 return &kexResult{ 137 H: h.Sum(nil), 138 K: K, 139 HostKey: kexDHReply.HostKey, 140 Signature: kexDHReply.Signature, 141 Hash: crypto.SHA1, 142 }, nil 143} 144 145func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 146 hashFunc := crypto.SHA1 147 packet, err := c.readPacket() 148 if err != nil { 149 return 150 } 151 var kexDHInit kexDHInitMsg 152 if err = Unmarshal(packet, &kexDHInit); err != nil { 153 return 154 } 155 156 var y *big.Int 157 for { 158 if y, err = rand.Int(randSource, group.pMinus1); err != nil { 159 return 160 } 161 if y.Sign() > 0 { 162 break 163 } 164 } 165 166 Y := new(big.Int).Exp(group.g, y, group.p) 167 ki, err := group.diffieHellman(kexDHInit.X, y) 168 if err != nil { 169 return nil, err 170 } 171 172 hostKeyBytes := priv.PublicKey().Marshal() 173 174 h := hashFunc.New() 175 magics.write(h) 176 writeString(h, hostKeyBytes) 177 writeInt(h, kexDHInit.X) 178 writeInt(h, Y) 179 180 K := make([]byte, intLength(ki)) 181 marshalInt(K, ki) 182 h.Write(K) 183 184 H := h.Sum(nil) 185 186 // H is already a hash, but the hostkey signing will apply its 187 // own key-specific hash algorithm. 188 sig, err := signAndMarshal(priv, randSource, H) 189 if err != nil { 190 return nil, err 191 } 192 193 kexDHReply := kexDHReplyMsg{ 194 HostKey: hostKeyBytes, 195 Y: Y, 196 Signature: sig, 197 } 198 packet = Marshal(&kexDHReply) 199 200 err = c.writePacket(packet) 201 return &kexResult{ 202 H: H, 203 K: K, 204 HostKey: hostKeyBytes, 205 Signature: sig, 206 Hash: crypto.SHA1, 207 }, nil 208} 209 210// ecdh performs Elliptic Curve Diffie-Hellman key exchange as 211// described in RFC 5656, section 4. 212type ecdh struct { 213 curve elliptic.Curve 214} 215 216func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 217 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 218 if err != nil { 219 return nil, err 220 } 221 222 kexInit := kexECDHInitMsg{ 223 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), 224 } 225 226 serialized := Marshal(&kexInit) 227 if err := c.writePacket(serialized); err != nil { 228 return nil, err 229 } 230 231 packet, err := c.readPacket() 232 if err != nil { 233 return nil, err 234 } 235 236 var reply kexECDHReplyMsg 237 if err = Unmarshal(packet, &reply); err != nil { 238 return nil, err 239 } 240 241 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) 242 if err != nil { 243 return nil, err 244 } 245 246 // generate shared secret 247 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) 248 249 h := ecHash(kex.curve).New() 250 magics.write(h) 251 writeString(h, reply.HostKey) 252 writeString(h, kexInit.ClientPubKey) 253 writeString(h, reply.EphemeralPubKey) 254 K := make([]byte, intLength(secret)) 255 marshalInt(K, secret) 256 h.Write(K) 257 258 return &kexResult{ 259 H: h.Sum(nil), 260 K: K, 261 HostKey: reply.HostKey, 262 Signature: reply.Signature, 263 Hash: ecHash(kex.curve), 264 }, nil 265} 266 267// unmarshalECKey parses and checks an EC key. 268func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { 269 x, y = elliptic.Unmarshal(curve, pubkey) 270 if x == nil { 271 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") 272 } 273 if !validateECPublicKey(curve, x, y) { 274 return nil, nil, errors.New("ssh: public key not on curve") 275 } 276 return x, y, nil 277} 278 279// validateECPublicKey checks that the point is a valid public key for 280// the given curve. See [SEC1], 3.2.2 281func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { 282 if x.Sign() == 0 && y.Sign() == 0 { 283 return false 284 } 285 286 if x.Cmp(curve.Params().P) >= 0 { 287 return false 288 } 289 290 if y.Cmp(curve.Params().P) >= 0 { 291 return false 292 } 293 294 if !curve.IsOnCurve(x, y) { 295 return false 296 } 297 298 // We don't check if N * PubKey == 0, since 299 // 300 // - the NIST curves have cofactor = 1, so this is implicit. 301 // (We don't foresee an implementation that supports non NIST 302 // curves) 303 // 304 // - for ephemeral keys, we don't need to worry about small 305 // subgroup attacks. 306 return true 307} 308 309func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 310 packet, err := c.readPacket() 311 if err != nil { 312 return nil, err 313 } 314 315 var kexECDHInit kexECDHInitMsg 316 if err = Unmarshal(packet, &kexECDHInit); err != nil { 317 return nil, err 318 } 319 320 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) 321 if err != nil { 322 return nil, err 323 } 324 325 // We could cache this key across multiple users/multiple 326 // connection attempts, but the benefit is small. OpenSSH 327 // generates a new key for each incoming connection. 328 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 329 if err != nil { 330 return nil, err 331 } 332 333 hostKeyBytes := priv.PublicKey().Marshal() 334 335 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) 336 337 // generate shared secret 338 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) 339 340 h := ecHash(kex.curve).New() 341 magics.write(h) 342 writeString(h, hostKeyBytes) 343 writeString(h, kexECDHInit.ClientPubKey) 344 writeString(h, serializedEphKey) 345 346 K := make([]byte, intLength(secret)) 347 marshalInt(K, secret) 348 h.Write(K) 349 350 H := h.Sum(nil) 351 352 // H is already a hash, but the hostkey signing will apply its 353 // own key-specific hash algorithm. 354 sig, err := signAndMarshal(priv, rand, H) 355 if err != nil { 356 return nil, err 357 } 358 359 reply := kexECDHReplyMsg{ 360 EphemeralPubKey: serializedEphKey, 361 HostKey: hostKeyBytes, 362 Signature: sig, 363 } 364 365 serialized := Marshal(&reply) 366 if err := c.writePacket(serialized); err != nil { 367 return nil, err 368 } 369 370 return &kexResult{ 371 H: H, 372 K: K, 373 HostKey: reply.HostKey, 374 Signature: sig, 375 Hash: ecHash(kex.curve), 376 }, nil 377} 378 379var kexAlgoMap = map[string]kexAlgorithm{} 380 381func init() { 382 // This is the group called diffie-hellman-group1-sha1 in RFC 383 // 4253 and Oakley Group 2 in RFC 2409. 384 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) 385 kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ 386 g: new(big.Int).SetInt64(2), 387 p: p, 388 pMinus1: new(big.Int).Sub(p, bigOne), 389 } 390 391 // This is the group called diffie-hellman-group14-sha1 in RFC 392 // 4253 and Oakley Group 14 in RFC 3526. 393 p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) 394 395 kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ 396 g: new(big.Int).SetInt64(2), 397 p: p, 398 pMinus1: new(big.Int).Sub(p, bigOne), 399 } 400 401 kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} 402 kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} 403 kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} 404 kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} 405} 406 407// curve25519sha256 implements the curve25519-sha256@libssh.org key 408// agreement protocol, as described in 409// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt 410type curve25519sha256 struct{} 411 412type curve25519KeyPair struct { 413 priv [32]byte 414 pub [32]byte 415} 416 417func (kp *curve25519KeyPair) generate(rand io.Reader) error { 418 if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { 419 return err 420 } 421 curve25519.ScalarBaseMult(&kp.pub, &kp.priv) 422 return nil 423} 424 425// curve25519Zeros is just an array of 32 zero bytes so that we have something 426// convenient to compare against in order to reject curve25519 points with the 427// wrong order. 428var curve25519Zeros [32]byte 429 430func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 431 var kp curve25519KeyPair 432 if err := kp.generate(rand); err != nil { 433 return nil, err 434 } 435 if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { 436 return nil, err 437 } 438 439 packet, err := c.readPacket() 440 if err != nil { 441 return nil, err 442 } 443 444 var reply kexECDHReplyMsg 445 if err = Unmarshal(packet, &reply); err != nil { 446 return nil, err 447 } 448 if len(reply.EphemeralPubKey) != 32 { 449 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 450 } 451 452 var servPub, secret [32]byte 453 copy(servPub[:], reply.EphemeralPubKey) 454 curve25519.ScalarMult(&secret, &kp.priv, &servPub) 455 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 456 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 457 } 458 459 h := crypto.SHA256.New() 460 magics.write(h) 461 writeString(h, reply.HostKey) 462 writeString(h, kp.pub[:]) 463 writeString(h, reply.EphemeralPubKey) 464 465 ki := new(big.Int).SetBytes(secret[:]) 466 K := make([]byte, intLength(ki)) 467 marshalInt(K, ki) 468 h.Write(K) 469 470 return &kexResult{ 471 H: h.Sum(nil), 472 K: K, 473 HostKey: reply.HostKey, 474 Signature: reply.Signature, 475 Hash: crypto.SHA256, 476 }, nil 477} 478 479func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 480 packet, err := c.readPacket() 481 if err != nil { 482 return 483 } 484 var kexInit kexECDHInitMsg 485 if err = Unmarshal(packet, &kexInit); err != nil { 486 return 487 } 488 489 if len(kexInit.ClientPubKey) != 32 { 490 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 491 } 492 493 var kp curve25519KeyPair 494 if err := kp.generate(rand); err != nil { 495 return nil, err 496 } 497 498 var clientPub, secret [32]byte 499 copy(clientPub[:], kexInit.ClientPubKey) 500 curve25519.ScalarMult(&secret, &kp.priv, &clientPub) 501 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 502 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 503 } 504 505 hostKeyBytes := priv.PublicKey().Marshal() 506 507 h := crypto.SHA256.New() 508 magics.write(h) 509 writeString(h, hostKeyBytes) 510 writeString(h, kexInit.ClientPubKey) 511 writeString(h, kp.pub[:]) 512 513 ki := new(big.Int).SetBytes(secret[:]) 514 K := make([]byte, intLength(ki)) 515 marshalInt(K, ki) 516 h.Write(K) 517 518 H := h.Sum(nil) 519 520 sig, err := signAndMarshal(priv, rand, H) 521 if err != nil { 522 return nil, err 523 } 524 525 reply := kexECDHReplyMsg{ 526 EphemeralPubKey: kp.pub[:], 527 HostKey: hostKeyBytes, 528 Signature: sig, 529 } 530 if err := c.writePacket(Marshal(&reply)); err != nil { 531 return nil, err 532 } 533 return &kexResult{ 534 H: H, 535 K: K, 536 HostKey: hostKeyBytes, 537 Signature: sig, 538 Hash: crypto.SHA256, 539 }, nil 540} 541