Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1077)

Side by Side Diff: ssh/kex.go

Issue 13352055: code review 13352055: go.crypto/ssh: separate kex algorithms into kexAlgorith... (Closed)
Patch Set: diff -r 3a49c11added https://code.google.com/p/go.crypto Created 10 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ssh/common.go ('k') | ssh/kex_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 package ssh
agl1 2013/09/24 15:11:11 Copyright comment.
hanwen-google 2013/09/24 15:28:26 Done.
2
3 import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rand"
8 "errors"
9 "io"
10 "math/big"
11 )
12
13 const (
14 kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
15 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
16 kexAlgoECDH256 = "ecdh-sha2-nistp256"
17 kexAlgoECDH384 = "ecdh-sha2-nistp384"
18 kexAlgoECDH521 = "ecdh-sha2-nistp521"
19 )
20
21 // kexResult captures the outcome of a key exchange.
22 type kexResult struct {
23 // Session hash. See also RFC 4253, section 8.
24 H []byte
25
26 // Shared secret. See also RFC 4253, section 8.
27 K []byte
28
29 // Host key as hashed into H
30 HostKey []byte
31
32 // Signature of H
33 Signature []byte
34 }
35
36 // Data that always goes into the session hash.
agl1 2013/09/24 15:11:11 // handshakeMagics contains data that is always in
hanwen-google 2013/09/24 15:28:26 Done.
37 type handshakeMagics struct {
38 clientVersion, serverVersion []byte
39 clientKexInit, serverKexInit []byte
40 }
41
42 func (m *handshakeMagics) write(w io.Writer) {
43 writeString(w, m.clientVersion)
44 writeString(w, m.serverVersion)
45 writeString(w, m.clientKexInit)
46 writeString(w, m.serverKexInit)
47 }
48
49 // kexAlgorithm abstracts different key exchange algorithms.
50 type kexAlgorithm interface {
51 Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
52 Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResul t, error)
53 Hash() crypto.Hash
agl1 2013/09/24 15:11:11 Hash needs a comment as it's not immediately obvio
hanwen-google 2013/09/24 15:28:26 Done.
54 }
55
56 // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman ke y agreement.
57 type dhGroup struct {
58 g, p *big.Int
59 }
60
61 func (group *dhGroup) Hash() crypto.Hash {
62 return crypto.SHA1
63 }
64
65 func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
66 if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
67 return nil, errors.New("ssh: DH parameter out of bounds")
68 }
69 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
70 }
71
72 func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha keMagics) (*kexResult, error) {
73 hashFunc := crypto.SHA1
74
75 x, err := rand.Int(randSource, group.p)
76 if err != nil {
77 return nil, err
78 }
79 X := new(big.Int).Exp(group.g, x, group.p)
80 kexDHInit := kexDHInitMsg{
81 X: X,
82 }
83 if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil {
84 return nil, err
85 }
86
87 packet, err := c.readPacket()
88 if err != nil {
89 return nil, err
90 }
91
92 var kexDHReply kexDHReplyMsg
93 if err = unmarshal(&kexDHReply, packet, msgKexDHReply); err != nil {
94 return nil, err
95 }
96
97 kInt, err := group.diffieHellman(kexDHReply.Y, x)
98 if err != nil {
99 return nil, err
100 }
101
102 h := hashFunc.New()
103 magics.write(h)
104 writeString(h, kexDHReply.HostKey)
105 writeInt(h, X)
106 writeInt(h, kexDHReply.Y)
107 K := make([]byte, intLength(kInt))
108 marshalInt(K, kInt)
109 h.Write(K)
110
111 return &kexResult{
112 H: h.Sum(nil),
113 K: K,
114 HostKey: kexDHReply.HostKey,
115 Signature: kexDHReply.Signature,
116 }, nil
117 }
118
119 func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha keMagics, priv Signer) (result *kexResult, err error) {
120 hashFunc := crypto.SHA1
121 packet, err := c.readPacket()
122 if err != nil {
123 return
124 }
125 var kexDHInit kexDHInitMsg
126 if err = unmarshal(&kexDHInit, packet, msgKexDHInit); err != nil {
127 return
128 }
129
130 y, err := rand.Int(randSource, group.p)
131 if err != nil {
132 return
133 }
134
135 Y := new(big.Int).Exp(group.g, y, group.p)
136 kInt, err := group.diffieHellman(kexDHInit.X, y)
137 if err != nil {
138 return nil, err
139 }
140
141 hostKeyBytes := MarshalPublicKey(priv.PublicKey())
142
143 h := hashFunc.New()
144 magics.write(h)
145 writeString(h, hostKeyBytes)
146 writeInt(h, kexDHInit.X)
147 writeInt(h, Y)
148
149 K := make([]byte, intLength(kInt))
150 marshalInt(K, kInt)
151 h.Write(K)
152
153 H := h.Sum(nil)
154
155 // H is already a hash, but the hostkey signing will apply its
156 // own key specific hash algorithm.
157 sig, err := signAndMarshal(priv, randSource, H)
158 if err != nil {
159 return nil, err
160 }
161
162 kexDHReply := kexDHReplyMsg{
163 HostKey: hostKeyBytes,
164 Y: Y,
165 Signature: sig,
166 }
167 packet = marshal(msgKexDHReply, kexDHReply)
168
169 err = c.writePacket(packet)
170 return &kexResult{
171 H: H,
172 K: K,
173 HostKey: hostKeyBytes,
174 Signature: sig,
175 }, nil
176 }
177
178 // ecdh performs Elliptic Curve Diffie-Hellman key exchange as
179 // described in RFC 5656, section 4.
180 type ecdh struct {
181 curve elliptic.Curve
182 }
183
184 func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) ( *kexResult, error) {
185 ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
186 if err != nil {
187 return nil, err
188 }
189
190 kexInit := kexECDHInitMsg{
191 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ep hKey.PublicKey.Y),
192 }
193
194 serialized := marshal(msgKexECDHInit, kexInit)
195 if err := c.writePacket(serialized); err != nil {
196 return nil, err
197 }
198
199 packet, err := c.readPacket()
200 if err != nil {
201 return nil, err
202 }
203
204 var reply kexECDHReplyMsg
205 if err = unmarshal(&reply, packet, msgKexECDHReply); err != nil {
206 return nil, err
207 }
208
209 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
210 if err != nil {
211 return nil, err
212 }
213
214 // generate shared secret
215 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
216
217 h := ecHash(kex.curve).New()
218 magics.write(h)
219 writeString(h, reply.HostKey)
220 writeString(h, kexInit.ClientPubKey)
221 writeString(h, reply.EphemeralPubKey)
222 K := make([]byte, intLength(secret))
223 marshalInt(K, secret)
224 h.Write(K)
225
226 return &kexResult{
227 H: h.Sum(nil),
228 K: K,
229 HostKey: reply.HostKey,
230 Signature: reply.Signature,
231 }, nil
232 }
233
234 func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err err or) {
235 x, y = elliptic.Unmarshal(curve, pubkey)
236 if x == nil {
237 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
238 }
239 if !validateECPublicKey(curve, x, y) {
240 return nil, nil, errors.New("ssh: public key not on curve")
241 }
242 return x, y, nil
243 }
244
245 func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, p riv Signer) (result *kexResult, err error) {
246 packet, err := c.readPacket()
247 if err != nil {
248 return nil, err
249 }
250
251 var kexECDHInit kexECDHInitMsg
252 if err = unmarshal(&kexECDHInit, packet, msgKexECDHInit); err != nil {
253 return nil, err
254 }
255
256 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPub Key)
257 if err != nil {
258 return nil, err
259 }
260
261 // We could cache this key across multiple users/multiple
262 // connection attempts, but the benefit is small. OpenSSH
263 // generates a new key for each incoming connection.
264 ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
265 if err != nil {
266 return nil, err
267 }
268
269 hostKeyBytes := MarshalPublicKey(priv.PublicKey())
270
271 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephK ey.PublicKey.Y)
272
273 // generate shared secret
274 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
275
276 h := ecHash(kex.curve).New()
277 magics.write(h)
278 writeString(h, hostKeyBytes)
279 writeString(h, kexECDHInit.ClientPubKey)
280 writeString(h, serializedEphKey)
281
282 K := make([]byte, intLength(secret))
283 marshalInt(K, secret)
284 h.Write(K)
285
286 H := h.Sum(nil)
287
288 // H is already a hash, but the hostkey signing will apply its
289 // own key specific hash algorithm.
290 sig, err := signAndMarshal(priv, rand, H)
291 if err != nil {
292 return nil, err
293 }
294
295 reply := kexECDHReplyMsg{
296 EphemeralPubKey: serializedEphKey,
297 HostKey: hostKeyBytes,
298 Signature: sig,
299 }
300
301 serialized := marshal(msgKexECDHReply, reply)
302 if err := c.writePacket(serialized); err != nil {
303 return nil, err
304 }
305
306 return &kexResult{
307 H: H,
308 K: K,
309 HostKey: reply.HostKey,
310 Signature: sig,
311 }, nil
312 }
313
314 func (kex *ecdh) Hash() crypto.Hash {
315 return ecHash(kex.curve)
316 }
317
318 var kexAlgoMap = map[string]kexAlgorithm{}
319
320 func init() {
321 // This is the group called diffie-hellman-group1-sha1 in RFC
322 // 4253 and Oakley Group 2 in RFC 2409.
323 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B 80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6D F25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB 5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
324 kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
325 g: new(big.Int).SetInt64(2),
326 p: p,
327 }
328
329 // This is the group called diffie-hellman-group14-sha1 in RFC
330 // 4253 and Oakley Group 14 in RFC 3526.
331 p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B8 0DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF 25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5 A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8F D24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08C A18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69 55817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
332
333 kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
334 g: new(big.Int).SetInt64(2),
335 p: p,
336 }
337
338 kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
339 kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
340 kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
341 }
OLDNEW
« no previous file with comments | « ssh/common.go ('k') | ssh/kex_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b