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.
18
kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
19
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
20
kexAlgoECDH256 = "ecdh-sha2-nistp256"
21
kexAlgoECDH384 = "ecdh-sha2-nistp384"
22
kexAlgoECDH521 = "ecdh-sha2-nistp521"
25
// kexResult captures the outcome of a key exchange.
26
type kexResult struct {
27
// Session hash. See also RFC 4253, section 8.
30
// Shared secret. See also RFC 4253, section 8.
33
// Host key as hashed into H
39
// A cryptographic hash function that matches the security
40
// level of the key exchange algorithm. It is used for
41
// calculating H, and for deriving keys from H and K.
44
// The session ID, which is the first H computed. This is used
45
// to signal data inside transport.
49
// handshakeMagics contains data that is always included in the
51
type handshakeMagics struct {
52
clientVersion, serverVersion []byte
53
clientKexInit, serverKexInit []byte
56
func (m *handshakeMagics) write(w io.Writer) {
57
writeString(w, m.clientVersion)
58
writeString(w, m.serverVersion)
59
writeString(w, m.clientKexInit)
60
writeString(w, m.serverKexInit)
63
// kexAlgorithm abstracts different key exchange algorithms.
64
type kexAlgorithm interface {
65
// Server runs server-side key agreement, signing the result
67
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
69
// Client runs the client-side key agreement. Caller is
70
// responsible for verifying the host key signature.
71
Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
74
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
79
func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
80
if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
81
return nil, errors.New("ssh: DH parameter out of bounds")
83
return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
86
func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
87
hashFunc := crypto.SHA1
89
x, err := rand.Int(randSource, group.p)
93
X := new(big.Int).Exp(group.g, x, group.p)
94
kexDHInit := kexDHInitMsg{
97
if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil {
101
packet, err := c.readPacket()
106
var kexDHReply kexDHReplyMsg
107
if err = unmarshal(&kexDHReply, packet, msgKexDHReply); err != nil {
111
kInt, err := group.diffieHellman(kexDHReply.Y, x)
118
writeString(h, kexDHReply.HostKey)
120
writeInt(h, kexDHReply.Y)
121
K := make([]byte, intLength(kInt))
128
HostKey: kexDHReply.HostKey,
129
Signature: kexDHReply.Signature,
134
func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
135
hashFunc := crypto.SHA1
136
packet, err := c.readPacket()
140
var kexDHInit kexDHInitMsg
141
if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil {
145
y, err := rand.Int(randSource, group.p)
150
Y := new(big.Int).Exp(group.g, y, group.p)
151
kInt, err := group.diffieHellman(kexDHInit.X, y)
156
hostKeyBytes := MarshalPublicKey(priv.PublicKey())
160
writeString(h, hostKeyBytes)
161
writeInt(h, kexDHInit.X)
164
K := make([]byte, intLength(kInt))
170
// H is already a hash, but the hostkey signing will apply its
171
// own key-specific hash algorithm.
172
sig, err := signAndMarshal(priv, randSource, H)
177
kexDHReply := kexDHReplyMsg{
178
HostKey: hostKeyBytes,
182
packet = marshal(msgKexDHReply, kexDHReply)
184
err = c.writePacket(packet)
188
HostKey: hostKeyBytes,
194
// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
195
// described in RFC 5656, section 4.
200
func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
201
ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
206
kexInit := kexECDHInitMsg{
207
ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
210
serialized := marshal(msgKexECDHInit, kexInit)
211
if err := c.writePacket(serialized); err != nil {
215
packet, err := c.readPacket()
220
var reply kexECDHReplyMsg
221
if err = unmarshal(&reply, packet, msgKexECDHReply); err != nil {
225
x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
230
// generate shared secret
231
secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
233
h := ecHash(kex.curve).New()
235
writeString(h, reply.HostKey)
236
writeString(h, kexInit.ClientPubKey)
237
writeString(h, reply.EphemeralPubKey)
238
K := make([]byte, intLength(secret))
239
marshalInt(K, secret)
245
HostKey: reply.HostKey,
246
Signature: reply.Signature,
247
Hash: ecHash(kex.curve),
251
// unmarshalECKey parses and checks an EC key.
252
func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
253
x, y = elliptic.Unmarshal(curve, pubkey)
255
return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
257
if !validateECPublicKey(curve, x, y) {
258
return nil, nil, errors.New("ssh: public key not on curve")
263
// validateECPublicKey checks that the point is a valid public key for
264
// the given curve. See [SEC1], 3.2.2
265
func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
266
if x.Sign() == 0 && y.Sign() == 0 {
270
if x.Cmp(curve.Params().P) >= 0 {
274
if y.Cmp(curve.Params().P) >= 0 {
278
if !curve.IsOnCurve(x, y) {
282
// We don't check if N * PubKey == 0, since
284
// - the NIST curves have cofactor = 1, so this is implicit.
285
// (We don't foresee an implementation that supports non NIST
288
// - for ephemeral keys, we don't need to worry about small
293
func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
294
packet, err := c.readPacket()
299
var kexECDHInit kexECDHInitMsg
300
if err = unmarshal(&kexECDHInit, packet, msgKexECDHInit); err != nil {
304
clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
309
// We could cache this key across multiple users/multiple
310
// connection attempts, but the benefit is small. OpenSSH
311
// generates a new key for each incoming connection.
312
ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
317
hostKeyBytes := MarshalPublicKey(priv.PublicKey())
319
serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
321
// generate shared secret
322
secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
324
h := ecHash(kex.curve).New()
326
writeString(h, hostKeyBytes)
327
writeString(h, kexECDHInit.ClientPubKey)
328
writeString(h, serializedEphKey)
330
K := make([]byte, intLength(secret))
331
marshalInt(K, secret)
336
// H is already a hash, but the hostkey signing will apply its
337
// own key-specific hash algorithm.
338
sig, err := signAndMarshal(priv, rand, H)
343
reply := kexECDHReplyMsg{
344
EphemeralPubKey: serializedEphKey,
345
HostKey: hostKeyBytes,
349
serialized := marshal(msgKexECDHReply, reply)
350
if err := c.writePacket(serialized); err != nil {
357
HostKey: reply.HostKey,
359
Hash: ecHash(kex.curve),
363
var kexAlgoMap = map[string]kexAlgorithm{}
366
// This is the group called diffie-hellman-group1-sha1 in RFC
367
// 4253 and Oakley Group 2 in RFC 2409.
368
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
369
kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
370
g: new(big.Int).SetInt64(2),
374
// This is the group called diffie-hellman-group14-sha1 in RFC
375
// 4253 and Oakley Group 14 in RFC 3526.
376
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
378
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
379
g: new(big.Int).SetInt64(2),
383
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
384
kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
385
kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}