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 "encoding/binary" 14 "errors" 15 "fmt" 16 "io" 17 "math/big" 18 19 "golang.org/x/crypto/curve25519" 20) 21 22const ( 23 kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" 24 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" 25 kexAlgoECDH256 = "ecdh-sha2-nistp256" 26 kexAlgoECDH384 = "ecdh-sha2-nistp384" 27 kexAlgoECDH521 = "ecdh-sha2-nistp521" 28 kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" 29 30 // For the following kex only the client half contains a production 31 // ready implementation. The server half only consists of a minimal 32 // implementation to satisfy the automated tests. 33 kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1" 34 kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256" 35) 36 37// kexResult captures the outcome of a key exchange. 38type kexResult struct { 39 // Session hash. See also RFC 4253, section 8. 40 H []byte 41 42 // Shared secret. See also RFC 4253, section 8. 43 K []byte 44 45 // Host key as hashed into H. 46 HostKey []byte 47 48 // Signature of H. 49 Signature []byte 50 51 // A cryptographic hash function that matches the security 52 // level of the key exchange algorithm. It is used for 53 // calculating H, and for deriving keys from H and K. 54 Hash crypto.Hash 55 56 // The session ID, which is the first H computed. This is used 57 // to derive key material inside the transport. 58 SessionID []byte 59} 60 61// handshakeMagics contains data that is always included in the 62// session hash. 63type handshakeMagics struct { 64 clientVersion, serverVersion []byte 65 clientKexInit, serverKexInit []byte 66} 67 68func (m *handshakeMagics) write(w io.Writer) { 69 writeString(w, m.clientVersion) 70 writeString(w, m.serverVersion) 71 writeString(w, m.clientKexInit) 72 writeString(w, m.serverKexInit) 73} 74 75// kexAlgorithm abstracts different key exchange algorithms. 76type kexAlgorithm interface { 77 // Server runs server-side key agreement, signing the result 78 // with a hostkey. 79 Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) 80 81 // Client runs the client-side key agreement. Caller is 82 // responsible for verifying the host key signature. 83 Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) 84} 85 86// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. 87type dhGroup struct { 88 g, p, pMinus1 *big.Int 89} 90 91func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { 92 if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { 93 return nil, errors.New("ssh: DH parameter out of bounds") 94 } 95 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil 96} 97 98func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 99 hashFunc := crypto.SHA1 100 101 var x *big.Int 102 for { 103 var err error 104 if x, err = rand.Int(randSource, group.pMinus1); err != nil { 105 return nil, err 106 } 107 if x.Sign() > 0 { 108 break 109 } 110 } 111 112 X := new(big.Int).Exp(group.g, x, group.p) 113 kexDHInit := kexDHInitMsg{ 114 X: X, 115 } 116 if err := c.writePacket(Marshal(&kexDHInit)); err != nil { 117 return nil, err 118 } 119 120 packet, err := c.readPacket() 121 if err != nil { 122 return nil, err 123 } 124 125 var kexDHReply kexDHReplyMsg 126 if err = Unmarshal(packet, &kexDHReply); err != nil { 127 return nil, err 128 } 129 130 ki, err := group.diffieHellman(kexDHReply.Y, x) 131 if err != nil { 132 return nil, err 133 } 134 135 h := hashFunc.New() 136 magics.write(h) 137 writeString(h, kexDHReply.HostKey) 138 writeInt(h, X) 139 writeInt(h, kexDHReply.Y) 140 K := make([]byte, intLength(ki)) 141 marshalInt(K, ki) 142 h.Write(K) 143 144 return &kexResult{ 145 H: h.Sum(nil), 146 K: K, 147 HostKey: kexDHReply.HostKey, 148 Signature: kexDHReply.Signature, 149 Hash: crypto.SHA1, 150 }, nil 151} 152 153func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 154 hashFunc := crypto.SHA1 155 packet, err := c.readPacket() 156 if err != nil { 157 return 158 } 159 var kexDHInit kexDHInitMsg 160 if err = Unmarshal(packet, &kexDHInit); err != nil { 161 return 162 } 163 164 var y *big.Int 165 for { 166 if y, err = rand.Int(randSource, group.pMinus1); err != nil { 167 return 168 } 169 if y.Sign() > 0 { 170 break 171 } 172 } 173 174 Y := new(big.Int).Exp(group.g, y, group.p) 175 ki, err := group.diffieHellman(kexDHInit.X, y) 176 if err != nil { 177 return nil, err 178 } 179 180 hostKeyBytes := priv.PublicKey().Marshal() 181 182 h := hashFunc.New() 183 magics.write(h) 184 writeString(h, hostKeyBytes) 185 writeInt(h, kexDHInit.X) 186 writeInt(h, Y) 187 188 K := make([]byte, intLength(ki)) 189 marshalInt(K, ki) 190 h.Write(K) 191 192 H := h.Sum(nil) 193 194 // H is already a hash, but the hostkey signing will apply its 195 // own key-specific hash algorithm. 196 sig, err := signAndMarshal(priv, randSource, H) 197 if err != nil { 198 return nil, err 199 } 200 201 kexDHReply := kexDHReplyMsg{ 202 HostKey: hostKeyBytes, 203 Y: Y, 204 Signature: sig, 205 } 206 packet = Marshal(&kexDHReply) 207 208 err = c.writePacket(packet) 209 return &kexResult{ 210 H: H, 211 K: K, 212 HostKey: hostKeyBytes, 213 Signature: sig, 214 Hash: crypto.SHA1, 215 }, err 216} 217 218// ecdh performs Elliptic Curve Diffie-Hellman key exchange as 219// described in RFC 5656, section 4. 220type ecdh struct { 221 curve elliptic.Curve 222} 223 224func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 225 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 226 if err != nil { 227 return nil, err 228 } 229 230 kexInit := kexECDHInitMsg{ 231 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), 232 } 233 234 serialized := Marshal(&kexInit) 235 if err := c.writePacket(serialized); err != nil { 236 return nil, err 237 } 238 239 packet, err := c.readPacket() 240 if err != nil { 241 return nil, err 242 } 243 244 var reply kexECDHReplyMsg 245 if err = Unmarshal(packet, &reply); err != nil { 246 return nil, err 247 } 248 249 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) 250 if err != nil { 251 return nil, err 252 } 253 254 // generate shared secret 255 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) 256 257 h := ecHash(kex.curve).New() 258 magics.write(h) 259 writeString(h, reply.HostKey) 260 writeString(h, kexInit.ClientPubKey) 261 writeString(h, reply.EphemeralPubKey) 262 K := make([]byte, intLength(secret)) 263 marshalInt(K, secret) 264 h.Write(K) 265 266 return &kexResult{ 267 H: h.Sum(nil), 268 K: K, 269 HostKey: reply.HostKey, 270 Signature: reply.Signature, 271 Hash: ecHash(kex.curve), 272 }, nil 273} 274 275// unmarshalECKey parses and checks an EC key. 276func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { 277 x, y = elliptic.Unmarshal(curve, pubkey) 278 if x == nil { 279 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") 280 } 281 if !validateECPublicKey(curve, x, y) { 282 return nil, nil, errors.New("ssh: public key not on curve") 283 } 284 return x, y, nil 285} 286 287// validateECPublicKey checks that the point is a valid public key for 288// the given curve. See [SEC1], 3.2.2 289func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { 290 if x.Sign() == 0 && y.Sign() == 0 { 291 return false 292 } 293 294 if x.Cmp(curve.Params().P) >= 0 { 295 return false 296 } 297 298 if y.Cmp(curve.Params().P) >= 0 { 299 return false 300 } 301 302 if !curve.IsOnCurve(x, y) { 303 return false 304 } 305 306 // We don't check if N * PubKey == 0, since 307 // 308 // - the NIST curves have cofactor = 1, so this is implicit. 309 // (We don't foresee an implementation that supports non NIST 310 // curves) 311 // 312 // - for ephemeral keys, we don't need to worry about small 313 // subgroup attacks. 314 return true 315} 316 317func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 318 packet, err := c.readPacket() 319 if err != nil { 320 return nil, err 321 } 322 323 var kexECDHInit kexECDHInitMsg 324 if err = Unmarshal(packet, &kexECDHInit); err != nil { 325 return nil, err 326 } 327 328 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) 329 if err != nil { 330 return nil, err 331 } 332 333 // We could cache this key across multiple users/multiple 334 // connection attempts, but the benefit is small. OpenSSH 335 // generates a new key for each incoming connection. 336 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 337 if err != nil { 338 return nil, err 339 } 340 341 hostKeyBytes := priv.PublicKey().Marshal() 342 343 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) 344 345 // generate shared secret 346 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) 347 348 h := ecHash(kex.curve).New() 349 magics.write(h) 350 writeString(h, hostKeyBytes) 351 writeString(h, kexECDHInit.ClientPubKey) 352 writeString(h, serializedEphKey) 353 354 K := make([]byte, intLength(secret)) 355 marshalInt(K, secret) 356 h.Write(K) 357 358 H := h.Sum(nil) 359 360 // H is already a hash, but the hostkey signing will apply its 361 // own key-specific hash algorithm. 362 sig, err := signAndMarshal(priv, rand, H) 363 if err != nil { 364 return nil, err 365 } 366 367 reply := kexECDHReplyMsg{ 368 EphemeralPubKey: serializedEphKey, 369 HostKey: hostKeyBytes, 370 Signature: sig, 371 } 372 373 serialized := Marshal(&reply) 374 if err := c.writePacket(serialized); err != nil { 375 return nil, err 376 } 377 378 return &kexResult{ 379 H: H, 380 K: K, 381 HostKey: reply.HostKey, 382 Signature: sig, 383 Hash: ecHash(kex.curve), 384 }, nil 385} 386 387var kexAlgoMap = map[string]kexAlgorithm{} 388 389func init() { 390 // This is the group called diffie-hellman-group1-sha1 in RFC 391 // 4253 and Oakley Group 2 in RFC 2409. 392 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) 393 kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ 394 g: new(big.Int).SetInt64(2), 395 p: p, 396 pMinus1: new(big.Int).Sub(p, bigOne), 397 } 398 399 // This is the group called diffie-hellman-group14-sha1 in RFC 400 // 4253 and Oakley Group 14 in RFC 3526. 401 p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) 402 403 kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ 404 g: new(big.Int).SetInt64(2), 405 p: p, 406 pMinus1: new(big.Int).Sub(p, bigOne), 407 } 408 409 kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} 410 kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} 411 kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} 412 kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} 413 kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} 414 kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} 415} 416 417// curve25519sha256 implements the curve25519-sha256@libssh.org key 418// agreement protocol, as described in 419// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt 420type curve25519sha256 struct{} 421 422type curve25519KeyPair struct { 423 priv [32]byte 424 pub [32]byte 425} 426 427func (kp *curve25519KeyPair) generate(rand io.Reader) error { 428 if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { 429 return err 430 } 431 curve25519.ScalarBaseMult(&kp.pub, &kp.priv) 432 return nil 433} 434 435// curve25519Zeros is just an array of 32 zero bytes so that we have something 436// convenient to compare against in order to reject curve25519 points with the 437// wrong order. 438var curve25519Zeros [32]byte 439 440func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 441 var kp curve25519KeyPair 442 if err := kp.generate(rand); err != nil { 443 return nil, err 444 } 445 if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { 446 return nil, err 447 } 448 449 packet, err := c.readPacket() 450 if err != nil { 451 return nil, err 452 } 453 454 var reply kexECDHReplyMsg 455 if err = Unmarshal(packet, &reply); err != nil { 456 return nil, err 457 } 458 if len(reply.EphemeralPubKey) != 32 { 459 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 460 } 461 462 var servPub, secret [32]byte 463 copy(servPub[:], reply.EphemeralPubKey) 464 curve25519.ScalarMult(&secret, &kp.priv, &servPub) 465 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 466 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 467 } 468 469 h := crypto.SHA256.New() 470 magics.write(h) 471 writeString(h, reply.HostKey) 472 writeString(h, kp.pub[:]) 473 writeString(h, reply.EphemeralPubKey) 474 475 ki := new(big.Int).SetBytes(secret[:]) 476 K := make([]byte, intLength(ki)) 477 marshalInt(K, ki) 478 h.Write(K) 479 480 return &kexResult{ 481 H: h.Sum(nil), 482 K: K, 483 HostKey: reply.HostKey, 484 Signature: reply.Signature, 485 Hash: crypto.SHA256, 486 }, nil 487} 488 489func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 490 packet, err := c.readPacket() 491 if err != nil { 492 return 493 } 494 var kexInit kexECDHInitMsg 495 if err = Unmarshal(packet, &kexInit); err != nil { 496 return 497 } 498 499 if len(kexInit.ClientPubKey) != 32 { 500 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 501 } 502 503 var kp curve25519KeyPair 504 if err := kp.generate(rand); err != nil { 505 return nil, err 506 } 507 508 var clientPub, secret [32]byte 509 copy(clientPub[:], kexInit.ClientPubKey) 510 curve25519.ScalarMult(&secret, &kp.priv, &clientPub) 511 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 512 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 513 } 514 515 hostKeyBytes := priv.PublicKey().Marshal() 516 517 h := crypto.SHA256.New() 518 magics.write(h) 519 writeString(h, hostKeyBytes) 520 writeString(h, kexInit.ClientPubKey) 521 writeString(h, kp.pub[:]) 522 523 ki := new(big.Int).SetBytes(secret[:]) 524 K := make([]byte, intLength(ki)) 525 marshalInt(K, ki) 526 h.Write(K) 527 528 H := h.Sum(nil) 529 530 sig, err := signAndMarshal(priv, rand, H) 531 if err != nil { 532 return nil, err 533 } 534 535 reply := kexECDHReplyMsg{ 536 EphemeralPubKey: kp.pub[:], 537 HostKey: hostKeyBytes, 538 Signature: sig, 539 } 540 if err := c.writePacket(Marshal(&reply)); err != nil { 541 return nil, err 542 } 543 return &kexResult{ 544 H: H, 545 K: K, 546 HostKey: hostKeyBytes, 547 Signature: sig, 548 Hash: crypto.SHA256, 549 }, nil 550} 551 552// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and 553// diffie-hellman-group-exchange-sha256 key agreement protocols, 554// as described in RFC 4419 555type dhGEXSHA struct { 556 g, p *big.Int 557 hashFunc crypto.Hash 558} 559 560const ( 561 dhGroupExchangeMinimumBits = 2048 562 dhGroupExchangePreferredBits = 2048 563 dhGroupExchangeMaximumBits = 8192 564) 565 566func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { 567 if theirPublic.Sign() <= 0 || theirPublic.Cmp(gex.p) >= 0 { 568 return nil, fmt.Errorf("ssh: DH parameter out of bounds") 569 } 570 return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil 571} 572 573func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 574 // Send GexRequest 575 kexDHGexRequest := kexDHGexRequestMsg{ 576 MinBits: dhGroupExchangeMinimumBits, 577 PreferedBits: dhGroupExchangePreferredBits, 578 MaxBits: dhGroupExchangeMaximumBits, 579 } 580 if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil { 581 return nil, err 582 } 583 584 // Receive GexGroup 585 packet, err := c.readPacket() 586 if err != nil { 587 return nil, err 588 } 589 590 var kexDHGexGroup kexDHGexGroupMsg 591 if err = Unmarshal(packet, &kexDHGexGroup); err != nil { 592 return nil, err 593 } 594 595 // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits 596 if kexDHGexGroup.P.BitLen() < dhGroupExchangeMinimumBits || kexDHGexGroup.P.BitLen() > dhGroupExchangeMaximumBits { 597 return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", kexDHGexGroup.P.BitLen()) 598 } 599 600 gex.p = kexDHGexGroup.P 601 gex.g = kexDHGexGroup.G 602 603 // Check if g is safe by verifing that g > 1 and g < p - 1 604 one := big.NewInt(1) 605 var pMinusOne = &big.Int{} 606 pMinusOne.Sub(gex.p, one) 607 if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 { 608 return nil, fmt.Errorf("ssh: server provided gex g is not safe") 609 } 610 611 // Send GexInit 612 var pHalf = &big.Int{} 613 pHalf.Rsh(gex.p, 1) 614 x, err := rand.Int(randSource, pHalf) 615 if err != nil { 616 return nil, err 617 } 618 X := new(big.Int).Exp(gex.g, x, gex.p) 619 kexDHGexInit := kexDHGexInitMsg{ 620 X: X, 621 } 622 if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil { 623 return nil, err 624 } 625 626 // Receive GexReply 627 packet, err = c.readPacket() 628 if err != nil { 629 return nil, err 630 } 631 632 var kexDHGexReply kexDHGexReplyMsg 633 if err = Unmarshal(packet, &kexDHGexReply); err != nil { 634 return nil, err 635 } 636 637 kInt, err := gex.diffieHellman(kexDHGexReply.Y, x) 638 if err != nil { 639 return nil, err 640 } 641 642 // Check if k is safe by verifing that k > 1 and k < p - 1 643 if kInt.Cmp(one) != 1 && kInt.Cmp(pMinusOne) != -1 { 644 return nil, fmt.Errorf("ssh: derived k is not safe") 645 } 646 647 h := gex.hashFunc.New() 648 magics.write(h) 649 writeString(h, kexDHGexReply.HostKey) 650 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) 651 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) 652 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) 653 writeInt(h, gex.p) 654 writeInt(h, gex.g) 655 writeInt(h, X) 656 writeInt(h, kexDHGexReply.Y) 657 K := make([]byte, intLength(kInt)) 658 marshalInt(K, kInt) 659 h.Write(K) 660 661 return &kexResult{ 662 H: h.Sum(nil), 663 K: K, 664 HostKey: kexDHGexReply.HostKey, 665 Signature: kexDHGexReply.Signature, 666 Hash: gex.hashFunc, 667 }, nil 668} 669 670// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. 671// 672// This is a minimal implementation to satisfy the automated tests. 673func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 674 // Receive GexRequest 675 packet, err := c.readPacket() 676 if err != nil { 677 return 678 } 679 var kexDHGexRequest kexDHGexRequestMsg 680 if err = Unmarshal(packet, &kexDHGexRequest); err != nil { 681 return 682 } 683 684 // smoosh the user's preferred size into our own limits 685 if kexDHGexRequest.PreferedBits > dhGroupExchangeMaximumBits { 686 kexDHGexRequest.PreferedBits = dhGroupExchangeMaximumBits 687 } 688 if kexDHGexRequest.PreferedBits < dhGroupExchangeMinimumBits { 689 kexDHGexRequest.PreferedBits = dhGroupExchangeMinimumBits 690 } 691 // fix min/max if they're inconsistent. technically, we could just pout 692 // and hang up, but there's no harm in giving them the benefit of the 693 // doubt and just picking a bitsize for them. 694 if kexDHGexRequest.MinBits > kexDHGexRequest.PreferedBits { 695 kexDHGexRequest.MinBits = kexDHGexRequest.PreferedBits 696 } 697 if kexDHGexRequest.MaxBits < kexDHGexRequest.PreferedBits { 698 kexDHGexRequest.MaxBits = kexDHGexRequest.PreferedBits 699 } 700 701 // Send GexGroup 702 // This is the group called diffie-hellman-group14-sha1 in RFC 703 // 4253 and Oakley Group 14 in RFC 3526. 704 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) 705 gex.p = p 706 gex.g = big.NewInt(2) 707 708 kexDHGexGroup := kexDHGexGroupMsg{ 709 P: gex.p, 710 G: gex.g, 711 } 712 if err := c.writePacket(Marshal(&kexDHGexGroup)); err != nil { 713 return nil, err 714 } 715 716 // Receive GexInit 717 packet, err = c.readPacket() 718 if err != nil { 719 return 720 } 721 var kexDHGexInit kexDHGexInitMsg 722 if err = Unmarshal(packet, &kexDHGexInit); err != nil { 723 return 724 } 725 726 var pHalf = &big.Int{} 727 pHalf.Rsh(gex.p, 1) 728 729 y, err := rand.Int(randSource, pHalf) 730 if err != nil { 731 return 732 } 733 734 Y := new(big.Int).Exp(gex.g, y, gex.p) 735 kInt, err := gex.diffieHellman(kexDHGexInit.X, y) 736 if err != nil { 737 return nil, err 738 } 739 740 hostKeyBytes := priv.PublicKey().Marshal() 741 742 h := gex.hashFunc.New() 743 magics.write(h) 744 writeString(h, hostKeyBytes) 745 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) 746 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) 747 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) 748 writeInt(h, gex.p) 749 writeInt(h, gex.g) 750 writeInt(h, kexDHGexInit.X) 751 writeInt(h, Y) 752 753 K := make([]byte, intLength(kInt)) 754 marshalInt(K, kInt) 755 h.Write(K) 756 757 H := h.Sum(nil) 758 759 // H is already a hash, but the hostkey signing will apply its 760 // own key-specific hash algorithm. 761 sig, err := signAndMarshal(priv, randSource, H) 762 if err != nil { 763 return nil, err 764 } 765 766 kexDHGexReply := kexDHGexReplyMsg{ 767 HostKey: hostKeyBytes, 768 Y: Y, 769 Signature: sig, 770 } 771 packet = Marshal(&kexDHGexReply) 772 773 err = c.writePacket(packet) 774 775 return &kexResult{ 776 H: H, 777 K: K, 778 HostKey: hostKeyBytes, 779 Signature: sig, 780 Hash: gex.hashFunc, 781 }, err 782} 783