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.
17 "golang.org/x/crypto/curve25519"
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"
29 // kexResult captures the outcome of a key exchange.
30 type kexResult struct {
31 // Session hash. See also RFC 4253, section 8.
34 // Shared secret. See also RFC 4253, section 8.
37 // Host key as hashed into H.
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.
48 // The session ID, which is the first H computed. This is used
49 // to derive key material inside the transport.
53 // handshakeMagics contains data that is always included in the
55 type handshakeMagics struct {
56 clientVersion, serverVersion []byte
57 clientKexInit, serverKexInit []byte
60 func (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)
67 // kexAlgorithm abstracts different key exchange algorithms.
68 type kexAlgorithm interface {
69 // Server runs server-side key agreement, signing the result
71 Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
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)
78 // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
80 g, p, pMinus1 *big.Int
83 func (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")
87 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
90 func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
91 hashFunc := crypto.SHA1
96 if x, err = rand.Int(randSource, group.pMinus1); err != nil {
104 X := new(big.Int).Exp(group.g, x, group.p)
105 kexDHInit := kexDHInitMsg{
108 if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
112 packet, err := c.readPacket()
117 var kexDHReply kexDHReplyMsg
118 if err = Unmarshal(packet, &kexDHReply); err != nil {
122 ki, err := group.diffieHellman(kexDHReply.Y, x)
129 writeString(h, kexDHReply.HostKey)
131 writeInt(h, kexDHReply.Y)
132 K := make([]byte, intLength(ki))
139 HostKey: kexDHReply.HostKey,
140 Signature: kexDHReply.Signature,
145 func (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()
151 var kexDHInit kexDHInitMsg
152 if err = Unmarshal(packet, &kexDHInit); err != nil {
158 if y, err = rand.Int(randSource, group.pMinus1); err != nil {
166 Y := new(big.Int).Exp(group.g, y, group.p)
167 ki, err := group.diffieHellman(kexDHInit.X, y)
172 hostKeyBytes := priv.PublicKey().Marshal()
176 writeString(h, hostKeyBytes)
177 writeInt(h, kexDHInit.X)
180 K := make([]byte, intLength(ki))
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)
193 kexDHReply := kexDHReplyMsg{
194 HostKey: hostKeyBytes,
198 packet = Marshal(&kexDHReply)
200 err = c.writePacket(packet)
204 HostKey: hostKeyBytes,
210 // ecdh performs Elliptic Curve Diffie-Hellman key exchange as
211 // described in RFC 5656, section 4.
216 func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
217 ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
222 kexInit := kexECDHInitMsg{
223 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
226 serialized := Marshal(&kexInit)
227 if err := c.writePacket(serialized); err != nil {
231 packet, err := c.readPacket()
236 var reply kexECDHReplyMsg
237 if err = Unmarshal(packet, &reply); err != nil {
241 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
246 // generate shared secret
247 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
249 h := ecHash(kex.curve).New()
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)
261 HostKey: reply.HostKey,
262 Signature: reply.Signature,
263 Hash: ecHash(kex.curve),
267 // unmarshalECKey parses and checks an EC key.
268 func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
269 x, y = elliptic.Unmarshal(curve, pubkey)
271 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
273 if !validateECPublicKey(curve, x, y) {
274 return nil, nil, errors.New("ssh: public key not on curve")
279 // validateECPublicKey checks that the point is a valid public key for
280 // the given curve. See [SEC1], 3.2.2
281 func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
282 if x.Sign() == 0 && y.Sign() == 0 {
286 if x.Cmp(curve.Params().P) >= 0 {
290 if y.Cmp(curve.Params().P) >= 0 {
294 if !curve.IsOnCurve(x, y) {
298 // We don't check if N * PubKey == 0, since
300 // - the NIST curves have cofactor = 1, so this is implicit.
301 // (We don't foresee an implementation that supports non NIST
304 // - for ephemeral keys, we don't need to worry about small
309 func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
310 packet, err := c.readPacket()
315 var kexECDHInit kexECDHInitMsg
316 if err = Unmarshal(packet, &kexECDHInit); err != nil {
320 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
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)
333 hostKeyBytes := priv.PublicKey().Marshal()
335 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
337 // generate shared secret
338 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
340 h := ecHash(kex.curve).New()
342 writeString(h, hostKeyBytes)
343 writeString(h, kexECDHInit.ClientPubKey)
344 writeString(h, serializedEphKey)
346 K := make([]byte, intLength(secret))
347 marshalInt(K, secret)
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)
359 reply := kexECDHReplyMsg{
360 EphemeralPubKey: serializedEphKey,
361 HostKey: hostKeyBytes,
365 serialized := Marshal(&reply)
366 if err := c.writePacket(serialized); err != nil {
373 HostKey: reply.HostKey,
375 Hash: ecHash(kex.curve),
379 var kexAlgoMap = map[string]kexAlgorithm{}
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),
388 pMinus1: new(big.Int).Sub(p, bigOne),
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)
395 kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
396 g: new(big.Int).SetInt64(2),
398 pMinus1: new(big.Int).Sub(p, bigOne),
401 kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
402 kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
403 kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
404 kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
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
410 type curve25519sha256 struct{}
412 type curve25519KeyPair struct {
417 func (kp *curve25519KeyPair) generate(rand io.Reader) error {
418 if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
421 curve25519.ScalarBaseMult(&kp.pub, &kp.priv)
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
428 var curve25519Zeros [32]byte
430 func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
431 var kp curve25519KeyPair
432 if err := kp.generate(rand); err != nil {
435 if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
439 packet, err := c.readPacket()
444 var reply kexECDHReplyMsg
445 if err = Unmarshal(packet, &reply); err != nil {
448 if len(reply.EphemeralPubKey) != 32 {
449 return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
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")
459 h := crypto.SHA256.New()
461 writeString(h, reply.HostKey)
462 writeString(h, kp.pub[:])
463 writeString(h, reply.EphemeralPubKey)
465 ki := new(big.Int).SetBytes(secret[:])
466 K := make([]byte, intLength(ki))
473 HostKey: reply.HostKey,
474 Signature: reply.Signature,
479 func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
480 packet, err := c.readPacket()
484 var kexInit kexECDHInitMsg
485 if err = Unmarshal(packet, &kexInit); err != nil {
489 if len(kexInit.ClientPubKey) != 32 {
490 return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
493 var kp curve25519KeyPair
494 if err := kp.generate(rand); err != nil {
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")
505 hostKeyBytes := priv.PublicKey().Marshal()
507 h := crypto.SHA256.New()
509 writeString(h, hostKeyBytes)
510 writeString(h, kexInit.ClientPubKey)
511 writeString(h, kp.pub[:])
513 ki := new(big.Int).SetBytes(secret[:])
514 K := make([]byte, intLength(ki))
520 sig, err := signAndMarshal(priv, rand, H)
525 reply := kexECDHReplyMsg{
526 EphemeralPubKey: kp.pub[:],
527 HostKey: hostKeyBytes,
530 if err := c.writePacket(Marshal(&reply)); err != nil {
536 HostKey: hostKeyBytes,