a geicko-2 based round robin ranking system designed to test c++ battleship submissions
battleship.dunkirk.sh
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}