Left: | ||
Right: |
OLD | NEW |
---|---|
(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 } | |
OLD | NEW |