]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/golang.org/x/crypto/ssh/kex.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / golang.org / x / crypto / ssh / kex.go
CommitLineData
bae9f6d2
JC
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 kInt, 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(kInt))
133 marshalInt(K, kInt)
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 kInt, 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(kInt))
181 marshalInt(K, kInt)
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 kInt := new(big.Int).SetBytes(secret[:])
466 K := make([]byte, intLength(kInt))
467 marshalInt(K, kInt)
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 kInt := new(big.Int).SetBytes(secret[:])
514 K := make([]byte, intLength(kInt))
515 marshalInt(K, kInt)
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}