a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
at main 23 kB view raw
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 // This is the group called diffie-hellman-group1-sha1 in RFC 4253 and 24 // Oakley Group 2 in RFC 2409. 25 oakleyGroup2 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF" 26 // This is the group called diffie-hellman-group14-sha1 in RFC 4253 and 27 // Oakley Group 14 in RFC 3526. 28 oakleyGroup14 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF" 29 // This is the group called diffie-hellman-group15-sha512 in RFC 8268 and 30 // Oakley Group 15 in RFC 3526. 31 oakleyGroup15 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" 32 // This is the group called diffie-hellman-group16-sha512 in RFC 8268 and 33 // Oakley Group 16 in RFC 3526. 34 oakleyGroup16 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF" 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. algo is the negotiated algorithm, and may 79 // be a certificate type. 80 Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error) 81 82 // Client runs the client-side key agreement. Caller is 83 // responsible for verifying the host key signature. 84 Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) 85} 86 87// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. 88type dhGroup struct { 89 g, p, pMinus1 *big.Int 90 hashFunc crypto.Hash 91} 92 93func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { 94 if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { 95 return nil, errors.New("ssh: DH parameter out of bounds") 96 } 97 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil 98} 99 100func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 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 := group.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: group.hashFunc, 150 }, nil 151} 152 153func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { 154 packet, err := c.readPacket() 155 if err != nil { 156 return 157 } 158 var kexDHInit kexDHInitMsg 159 if err = Unmarshal(packet, &kexDHInit); err != nil { 160 return 161 } 162 163 var y *big.Int 164 for { 165 if y, err = rand.Int(randSource, group.pMinus1); err != nil { 166 return 167 } 168 if y.Sign() > 0 { 169 break 170 } 171 } 172 173 Y := new(big.Int).Exp(group.g, y, group.p) 174 ki, err := group.diffieHellman(kexDHInit.X, y) 175 if err != nil { 176 return nil, err 177 } 178 179 hostKeyBytes := priv.PublicKey().Marshal() 180 181 h := group.hashFunc.New() 182 magics.write(h) 183 writeString(h, hostKeyBytes) 184 writeInt(h, kexDHInit.X) 185 writeInt(h, Y) 186 187 K := make([]byte, intLength(ki)) 188 marshalInt(K, ki) 189 h.Write(K) 190 191 H := h.Sum(nil) 192 193 // H is already a hash, but the hostkey signing will apply its 194 // own key-specific hash algorithm. 195 sig, err := signAndMarshal(priv, randSource, H, algo) 196 if err != nil { 197 return nil, err 198 } 199 200 kexDHReply := kexDHReplyMsg{ 201 HostKey: hostKeyBytes, 202 Y: Y, 203 Signature: sig, 204 } 205 packet = Marshal(&kexDHReply) 206 207 err = c.writePacket(packet) 208 return &kexResult{ 209 H: H, 210 K: K, 211 HostKey: hostKeyBytes, 212 Signature: sig, 213 Hash: group.hashFunc, 214 }, err 215} 216 217// ecdh performs Elliptic Curve Diffie-Hellman key exchange as 218// described in RFC 5656, section 4. 219type ecdh struct { 220 curve elliptic.Curve 221} 222 223func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 224 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 225 if err != nil { 226 return nil, err 227 } 228 229 kexInit := kexECDHInitMsg{ 230 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), 231 } 232 233 serialized := Marshal(&kexInit) 234 if err := c.writePacket(serialized); err != nil { 235 return nil, err 236 } 237 238 packet, err := c.readPacket() 239 if err != nil { 240 return nil, err 241 } 242 243 var reply kexECDHReplyMsg 244 if err = Unmarshal(packet, &reply); err != nil { 245 return nil, err 246 } 247 248 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) 249 if err != nil { 250 return nil, err 251 } 252 253 // generate shared secret 254 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) 255 256 h := ecHash(kex.curve).New() 257 magics.write(h) 258 writeString(h, reply.HostKey) 259 writeString(h, kexInit.ClientPubKey) 260 writeString(h, reply.EphemeralPubKey) 261 K := make([]byte, intLength(secret)) 262 marshalInt(K, secret) 263 h.Write(K) 264 265 return &kexResult{ 266 H: h.Sum(nil), 267 K: K, 268 HostKey: reply.HostKey, 269 Signature: reply.Signature, 270 Hash: ecHash(kex.curve), 271 }, nil 272} 273 274// unmarshalECKey parses and checks an EC key. 275func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { 276 x, y = elliptic.Unmarshal(curve, pubkey) 277 if x == nil { 278 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") 279 } 280 if !validateECPublicKey(curve, x, y) { 281 return nil, nil, errors.New("ssh: public key not on curve") 282 } 283 return x, y, nil 284} 285 286// validateECPublicKey checks that the point is a valid public key for 287// the given curve. See [SEC1], 3.2.2 288func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { 289 if x.Sign() == 0 && y.Sign() == 0 { 290 return false 291 } 292 293 if x.Cmp(curve.Params().P) >= 0 { 294 return false 295 } 296 297 if y.Cmp(curve.Params().P) >= 0 { 298 return false 299 } 300 301 if !curve.IsOnCurve(x, y) { 302 return false 303 } 304 305 // We don't check if N * PubKey == 0, since 306 // 307 // - the NIST curves have cofactor = 1, so this is implicit. 308 // (We don't foresee an implementation that supports non NIST 309 // curves) 310 // 311 // - for ephemeral keys, we don't need to worry about small 312 // subgroup attacks. 313 return true 314} 315 316func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { 317 packet, err := c.readPacket() 318 if err != nil { 319 return nil, err 320 } 321 322 var kexECDHInit kexECDHInitMsg 323 if err = Unmarshal(packet, &kexECDHInit); err != nil { 324 return nil, err 325 } 326 327 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) 328 if err != nil { 329 return nil, err 330 } 331 332 // We could cache this key across multiple users/multiple 333 // connection attempts, but the benefit is small. OpenSSH 334 // generates a new key for each incoming connection. 335 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 336 if err != nil { 337 return nil, err 338 } 339 340 hostKeyBytes := priv.PublicKey().Marshal() 341 342 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) 343 344 // generate shared secret 345 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) 346 347 h := ecHash(kex.curve).New() 348 magics.write(h) 349 writeString(h, hostKeyBytes) 350 writeString(h, kexECDHInit.ClientPubKey) 351 writeString(h, serializedEphKey) 352 353 K := make([]byte, intLength(secret)) 354 marshalInt(K, secret) 355 h.Write(K) 356 357 H := h.Sum(nil) 358 359 // H is already a hash, but the hostkey signing will apply its 360 // own key-specific hash algorithm. 361 sig, err := signAndMarshal(priv, rand, H, algo) 362 if err != nil { 363 return nil, err 364 } 365 366 reply := kexECDHReplyMsg{ 367 EphemeralPubKey: serializedEphKey, 368 HostKey: hostKeyBytes, 369 Signature: sig, 370 } 371 372 serialized := Marshal(&reply) 373 if err := c.writePacket(serialized); err != nil { 374 return nil, err 375 } 376 377 return &kexResult{ 378 H: H, 379 K: K, 380 HostKey: reply.HostKey, 381 Signature: sig, 382 Hash: ecHash(kex.curve), 383 }, nil 384} 385 386// ecHash returns the hash to match the given elliptic curve, see RFC 387// 5656, section 6.2.1 388func ecHash(curve elliptic.Curve) crypto.Hash { 389 bitSize := curve.Params().BitSize 390 switch { 391 case bitSize <= 256: 392 return crypto.SHA256 393 case bitSize <= 384: 394 return crypto.SHA384 395 } 396 return crypto.SHA512 397} 398 399var kexAlgoMap = map[string]kexAlgorithm{} 400 401func init() { 402 p, _ := new(big.Int).SetString(oakleyGroup2, 16) 403 kexAlgoMap[InsecureKeyExchangeDH1SHA1] = &dhGroup{ 404 g: new(big.Int).SetInt64(2), 405 p: p, 406 pMinus1: new(big.Int).Sub(p, bigOne), 407 hashFunc: crypto.SHA1, 408 } 409 410 p, _ = new(big.Int).SetString(oakleyGroup14, 16) 411 group14 := &dhGroup{ 412 g: new(big.Int).SetInt64(2), 413 p: p, 414 pMinus1: new(big.Int).Sub(p, bigOne), 415 } 416 417 kexAlgoMap[InsecureKeyExchangeDH14SHA1] = &dhGroup{ 418 g: group14.g, p: group14.p, pMinus1: group14.pMinus1, 419 hashFunc: crypto.SHA1, 420 } 421 kexAlgoMap[KeyExchangeDH14SHA256] = &dhGroup{ 422 g: group14.g, p: group14.p, pMinus1: group14.pMinus1, 423 hashFunc: crypto.SHA256, 424 } 425 426 p, _ = new(big.Int).SetString(oakleyGroup16, 16) 427 428 kexAlgoMap[KeyExchangeDH16SHA512] = &dhGroup{ 429 g: new(big.Int).SetInt64(2), 430 p: p, 431 pMinus1: new(big.Int).Sub(p, bigOne), 432 hashFunc: crypto.SHA512, 433 } 434 435 kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()} 436 kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()} 437 kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()} 438 kexAlgoMap[KeyExchangeCurve25519] = &curve25519sha256{} 439 kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{} 440 kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} 441 kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} 442} 443 444// curve25519sha256 implements the curve25519-sha256 (formerly known as 445// curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731. 446type curve25519sha256 struct{} 447 448type curve25519KeyPair struct { 449 priv [32]byte 450 pub [32]byte 451} 452 453func (kp *curve25519KeyPair) generate(rand io.Reader) error { 454 if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { 455 return err 456 } 457 curve25519.ScalarBaseMult(&kp.pub, &kp.priv) 458 return nil 459} 460 461// curve25519Zeros is just an array of 32 zero bytes so that we have something 462// convenient to compare against in order to reject curve25519 points with the 463// wrong order. 464var curve25519Zeros [32]byte 465 466func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 467 var kp curve25519KeyPair 468 if err := kp.generate(rand); err != nil { 469 return nil, err 470 } 471 if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { 472 return nil, err 473 } 474 475 packet, err := c.readPacket() 476 if err != nil { 477 return nil, err 478 } 479 480 var reply kexECDHReplyMsg 481 if err = Unmarshal(packet, &reply); err != nil { 482 return nil, err 483 } 484 if len(reply.EphemeralPubKey) != 32 { 485 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 486 } 487 488 var servPub, secret [32]byte 489 copy(servPub[:], reply.EphemeralPubKey) 490 curve25519.ScalarMult(&secret, &kp.priv, &servPub) 491 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 492 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 493 } 494 495 h := crypto.SHA256.New() 496 magics.write(h) 497 writeString(h, reply.HostKey) 498 writeString(h, kp.pub[:]) 499 writeString(h, reply.EphemeralPubKey) 500 501 ki := new(big.Int).SetBytes(secret[:]) 502 K := make([]byte, intLength(ki)) 503 marshalInt(K, ki) 504 h.Write(K) 505 506 return &kexResult{ 507 H: h.Sum(nil), 508 K: K, 509 HostKey: reply.HostKey, 510 Signature: reply.Signature, 511 Hash: crypto.SHA256, 512 }, nil 513} 514 515func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { 516 packet, err := c.readPacket() 517 if err != nil { 518 return 519 } 520 var kexInit kexECDHInitMsg 521 if err = Unmarshal(packet, &kexInit); err != nil { 522 return 523 } 524 525 if len(kexInit.ClientPubKey) != 32 { 526 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 527 } 528 529 var kp curve25519KeyPair 530 if err := kp.generate(rand); err != nil { 531 return nil, err 532 } 533 534 var clientPub, secret [32]byte 535 copy(clientPub[:], kexInit.ClientPubKey) 536 curve25519.ScalarMult(&secret, &kp.priv, &clientPub) 537 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 538 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 539 } 540 541 hostKeyBytes := priv.PublicKey().Marshal() 542 543 h := crypto.SHA256.New() 544 magics.write(h) 545 writeString(h, hostKeyBytes) 546 writeString(h, kexInit.ClientPubKey) 547 writeString(h, kp.pub[:]) 548 549 ki := new(big.Int).SetBytes(secret[:]) 550 K := make([]byte, intLength(ki)) 551 marshalInt(K, ki) 552 h.Write(K) 553 554 H := h.Sum(nil) 555 556 sig, err := signAndMarshal(priv, rand, H, algo) 557 if err != nil { 558 return nil, err 559 } 560 561 reply := kexECDHReplyMsg{ 562 EphemeralPubKey: kp.pub[:], 563 HostKey: hostKeyBytes, 564 Signature: sig, 565 } 566 if err := c.writePacket(Marshal(&reply)); err != nil { 567 return nil, err 568 } 569 return &kexResult{ 570 H: H, 571 K: K, 572 HostKey: hostKeyBytes, 573 Signature: sig, 574 Hash: crypto.SHA256, 575 }, nil 576} 577 578// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and 579// diffie-hellman-group-exchange-sha256 key agreement protocols, 580// as described in RFC 4419 581type dhGEXSHA struct { 582 hashFunc crypto.Hash 583} 584 585const ( 586 dhGroupExchangeMinimumBits = 2048 587 dhGroupExchangePreferredBits = 2048 588 dhGroupExchangeMaximumBits = 8192 589) 590 591func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 592 // Send GexRequest 593 kexDHGexRequest := kexDHGexRequestMsg{ 594 MinBits: dhGroupExchangeMinimumBits, 595 PreferredBits: dhGroupExchangePreferredBits, 596 MaxBits: dhGroupExchangeMaximumBits, 597 } 598 if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil { 599 return nil, err 600 } 601 602 // Receive GexGroup 603 packet, err := c.readPacket() 604 if err != nil { 605 return nil, err 606 } 607 608 var msg kexDHGexGroupMsg 609 if err = Unmarshal(packet, &msg); err != nil { 610 return nil, err 611 } 612 613 // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits 614 if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits { 615 return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen()) 616 } 617 618 // Check if g is safe by verifying that 1 < g < p-1 619 pMinusOne := new(big.Int).Sub(msg.P, bigOne) 620 if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 { 621 return nil, fmt.Errorf("ssh: server provided gex g is not safe") 622 } 623 624 // Send GexInit 625 pHalf := new(big.Int).Rsh(msg.P, 1) 626 x, err := rand.Int(randSource, pHalf) 627 if err != nil { 628 return nil, err 629 } 630 X := new(big.Int).Exp(msg.G, x, msg.P) 631 kexDHGexInit := kexDHGexInitMsg{ 632 X: X, 633 } 634 if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil { 635 return nil, err 636 } 637 638 // Receive GexReply 639 packet, err = c.readPacket() 640 if err != nil { 641 return nil, err 642 } 643 644 var kexDHGexReply kexDHGexReplyMsg 645 if err = Unmarshal(packet, &kexDHGexReply); err != nil { 646 return nil, err 647 } 648 649 if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 { 650 return nil, errors.New("ssh: DH parameter out of bounds") 651 } 652 kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P) 653 654 // Check if k is safe by verifying that k > 1 and k < p - 1 655 if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 { 656 return nil, fmt.Errorf("ssh: derived k is not safe") 657 } 658 659 h := gex.hashFunc.New() 660 magics.write(h) 661 writeString(h, kexDHGexReply.HostKey) 662 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) 663 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) 664 binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) 665 writeInt(h, msg.P) 666 writeInt(h, msg.G) 667 writeInt(h, X) 668 writeInt(h, kexDHGexReply.Y) 669 K := make([]byte, intLength(kInt)) 670 marshalInt(K, kInt) 671 h.Write(K) 672 673 return &kexResult{ 674 H: h.Sum(nil), 675 K: K, 676 HostKey: kexDHGexReply.HostKey, 677 Signature: kexDHGexReply.Signature, 678 Hash: gex.hashFunc, 679 }, nil 680} 681 682// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. 683func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { 684 // Receive GexRequest 685 packet, err := c.readPacket() 686 if err != nil { 687 return 688 } 689 var kexDHGexRequest kexDHGexRequestMsg 690 if err = Unmarshal(packet, &kexDHGexRequest); err != nil { 691 return 692 } 693 // We check that the request received is valid and that the MaxBits 694 // requested are at least equal to our supported minimum. This is the same 695 // check done in OpenSSH: 696 // https://github.com/openssh/openssh-portable/blob/80a2f64b/kexgexs.c#L94 697 // 698 // Furthermore, we also check that the required MinBits are less than or 699 // equal to 4096 because we can use up to Oakley Group 16. 700 if kexDHGexRequest.MaxBits < kexDHGexRequest.MinBits || kexDHGexRequest.PreferredBits < kexDHGexRequest.MinBits || 701 kexDHGexRequest.MaxBits < kexDHGexRequest.PreferredBits || kexDHGexRequest.MaxBits < dhGroupExchangeMinimumBits || 702 kexDHGexRequest.MinBits > 4096 { 703 return nil, fmt.Errorf("ssh: DH GEX request out of range, min: %d, max: %d, preferred: %d", kexDHGexRequest.MinBits, 704 kexDHGexRequest.MaxBits, kexDHGexRequest.PreferredBits) 705 } 706 707 var p *big.Int 708 // We hardcode sending Oakley Group 14 (2048 bits), Oakley Group 15 (3072 709 // bits) or Oakley Group 16 (4096 bits), based on the requested max size. 710 if kexDHGexRequest.MaxBits < 3072 { 711 p, _ = new(big.Int).SetString(oakleyGroup14, 16) 712 } else if kexDHGexRequest.MaxBits < 4096 { 713 p, _ = new(big.Int).SetString(oakleyGroup15, 16) 714 } else { 715 p, _ = new(big.Int).SetString(oakleyGroup16, 16) 716 } 717 718 g := big.NewInt(2) 719 msg := &kexDHGexGroupMsg{ 720 P: p, 721 G: g, 722 } 723 if err := c.writePacket(Marshal(msg)); err != nil { 724 return nil, err 725 } 726 727 // Receive GexInit 728 packet, err = c.readPacket() 729 if err != nil { 730 return 731 } 732 var kexDHGexInit kexDHGexInitMsg 733 if err = Unmarshal(packet, &kexDHGexInit); err != nil { 734 return 735 } 736 737 pHalf := new(big.Int).Rsh(p, 1) 738 739 y, err := rand.Int(randSource, pHalf) 740 if err != nil { 741 return 742 } 743 Y := new(big.Int).Exp(g, y, p) 744 745 pMinusOne := new(big.Int).Sub(p, bigOne) 746 if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 { 747 return nil, errors.New("ssh: DH parameter out of bounds") 748 } 749 kInt := new(big.Int).Exp(kexDHGexInit.X, y, p) 750 751 hostKeyBytes := priv.PublicKey().Marshal() 752 753 h := gex.hashFunc.New() 754 magics.write(h) 755 writeString(h, hostKeyBytes) 756 binary.Write(h, binary.BigEndian, kexDHGexRequest.MinBits) 757 binary.Write(h, binary.BigEndian, kexDHGexRequest.PreferredBits) 758 binary.Write(h, binary.BigEndian, kexDHGexRequest.MaxBits) 759 writeInt(h, p) 760 writeInt(h, g) 761 writeInt(h, kexDHGexInit.X) 762 writeInt(h, Y) 763 764 K := make([]byte, intLength(kInt)) 765 marshalInt(K, kInt) 766 h.Write(K) 767 768 H := h.Sum(nil) 769 770 // H is already a hash, but the hostkey signing will apply its 771 // own key-specific hash algorithm. 772 sig, err := signAndMarshal(priv, randSource, H, algo) 773 if err != nil { 774 return nil, err 775 } 776 777 kexDHGexReply := kexDHGexReplyMsg{ 778 HostKey: hostKeyBytes, 779 Y: Y, 780 Signature: sig, 781 } 782 packet = Marshal(&kexDHGexReply) 783 784 err = c.writePacket(packet) 785 786 return &kexResult{ 787 H: H, 788 K: K, 789 HostKey: hostKeyBytes, 790 Signature: sig, 791 Hash: gex.hashFunc, 792 }, err 793}