github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/crypto/ssh/kex.go (about) 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 5 package ssh 6 7 import ( 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 20 const ( 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. 30 type 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 signal data inside transport. 50 SessionID []byte 51 } 52 53 // handshakeMagics contains data that is always included in the 54 // session hash. 55 type handshakeMagics struct { 56 clientVersion, serverVersion []byte 57 clientKexInit, serverKexInit []byte 58 } 59 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) 65 } 66 67 // kexAlgorithm abstracts different key exchange algorithms. 68 type 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. 79 type dhGroup struct { 80 g, p *big.Int 81 } 82 83 func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { 84 if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 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 90 func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { 91 hashFunc := crypto.SHA1 92 93 x, err := rand.Int(randSource, group.p) 94 if err != nil { 95 return nil, err 96 } 97 X := new(big.Int).Exp(group.g, x, group.p) 98 kexDHInit := kexDHInitMsg{ 99 X: X, 100 } 101 if err := c.writePacket(Marshal(&kexDHInit)); err != nil { 102 return nil, err 103 } 104 105 packet, err := c.readPacket() 106 if err != nil { 107 return nil, err 108 } 109 110 var kexDHReply kexDHReplyMsg 111 if err = Unmarshal(packet, &kexDHReply); err != nil { 112 return nil, err 113 } 114 115 kInt, err := group.diffieHellman(kexDHReply.Y, x) 116 if err != nil { 117 return nil, err 118 } 119 120 h := hashFunc.New() 121 magics.write(h) 122 writeString(h, kexDHReply.HostKey) 123 writeInt(h, X) 124 writeInt(h, kexDHReply.Y) 125 K := make([]byte, intLength(kInt)) 126 marshalInt(K, kInt) 127 h.Write(K) 128 129 return &kexResult{ 130 H: h.Sum(nil), 131 K: K, 132 HostKey: kexDHReply.HostKey, 133 Signature: kexDHReply.Signature, 134 Hash: crypto.SHA1, 135 }, nil 136 } 137 138 func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 139 hashFunc := crypto.SHA1 140 packet, err := c.readPacket() 141 if err != nil { 142 return 143 } 144 var kexDHInit kexDHInitMsg 145 if err = Unmarshal(packet, &kexDHInit); err != nil { 146 return 147 } 148 149 y, err := rand.Int(randSource, group.p) 150 if err != nil { 151 return 152 } 153 154 Y := new(big.Int).Exp(group.g, y, group.p) 155 kInt, err := group.diffieHellman(kexDHInit.X, y) 156 if err != nil { 157 return nil, err 158 } 159 160 hostKeyBytes := priv.PublicKey().Marshal() 161 162 h := hashFunc.New() 163 magics.write(h) 164 writeString(h, hostKeyBytes) 165 writeInt(h, kexDHInit.X) 166 writeInt(h, Y) 167 168 K := make([]byte, intLength(kInt)) 169 marshalInt(K, kInt) 170 h.Write(K) 171 172 H := h.Sum(nil) 173 174 // H is already a hash, but the hostkey signing will apply its 175 // own key-specific hash algorithm. 176 sig, err := signAndMarshal(priv, randSource, H) 177 if err != nil { 178 return nil, err 179 } 180 181 kexDHReply := kexDHReplyMsg{ 182 HostKey: hostKeyBytes, 183 Y: Y, 184 Signature: sig, 185 } 186 packet = Marshal(&kexDHReply) 187 188 err = c.writePacket(packet) 189 return &kexResult{ 190 H: H, 191 K: K, 192 HostKey: hostKeyBytes, 193 Signature: sig, 194 Hash: crypto.SHA1, 195 }, nil 196 } 197 198 // ecdh performs Elliptic Curve Diffie-Hellman key exchange as 199 // described in RFC 5656, section 4. 200 type ecdh struct { 201 curve elliptic.Curve 202 } 203 204 func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 205 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 206 if err != nil { 207 return nil, err 208 } 209 210 kexInit := kexECDHInitMsg{ 211 ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), 212 } 213 214 serialized := Marshal(&kexInit) 215 if err := c.writePacket(serialized); err != nil { 216 return nil, err 217 } 218 219 packet, err := c.readPacket() 220 if err != nil { 221 return nil, err 222 } 223 224 var reply kexECDHReplyMsg 225 if err = Unmarshal(packet, &reply); err != nil { 226 return nil, err 227 } 228 229 x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) 230 if err != nil { 231 return nil, err 232 } 233 234 // generate shared secret 235 secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) 236 237 h := ecHash(kex.curve).New() 238 magics.write(h) 239 writeString(h, reply.HostKey) 240 writeString(h, kexInit.ClientPubKey) 241 writeString(h, reply.EphemeralPubKey) 242 K := make([]byte, intLength(secret)) 243 marshalInt(K, secret) 244 h.Write(K) 245 246 return &kexResult{ 247 H: h.Sum(nil), 248 K: K, 249 HostKey: reply.HostKey, 250 Signature: reply.Signature, 251 Hash: ecHash(kex.curve), 252 }, nil 253 } 254 255 // unmarshalECKey parses and checks an EC key. 256 func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { 257 x, y = elliptic.Unmarshal(curve, pubkey) 258 if x == nil { 259 return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") 260 } 261 if !validateECPublicKey(curve, x, y) { 262 return nil, nil, errors.New("ssh: public key not on curve") 263 } 264 return x, y, nil 265 } 266 267 // validateECPublicKey checks that the point is a valid public key for 268 // the given curve. See [SEC1], 3.2.2 269 func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { 270 if x.Sign() == 0 && y.Sign() == 0 { 271 return false 272 } 273 274 if x.Cmp(curve.Params().P) >= 0 { 275 return false 276 } 277 278 if y.Cmp(curve.Params().P) >= 0 { 279 return false 280 } 281 282 if !curve.IsOnCurve(x, y) { 283 return false 284 } 285 286 // We don't check if N * PubKey == 0, since 287 // 288 // - the NIST curves have cofactor = 1, so this is implicit. 289 // (We don't foresee an implementation that supports non NIST 290 // curves) 291 // 292 // - for ephemeral keys, we don't need to worry about small 293 // subgroup attacks. 294 return true 295 } 296 297 func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 298 packet, err := c.readPacket() 299 if err != nil { 300 return nil, err 301 } 302 303 var kexECDHInit kexECDHInitMsg 304 if err = Unmarshal(packet, &kexECDHInit); err != nil { 305 return nil, err 306 } 307 308 clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) 309 if err != nil { 310 return nil, err 311 } 312 313 // We could cache this key across multiple users/multiple 314 // connection attempts, but the benefit is small. OpenSSH 315 // generates a new key for each incoming connection. 316 ephKey, err := ecdsa.GenerateKey(kex.curve, rand) 317 if err != nil { 318 return nil, err 319 } 320 321 hostKeyBytes := priv.PublicKey().Marshal() 322 323 serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) 324 325 // generate shared secret 326 secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) 327 328 h := ecHash(kex.curve).New() 329 magics.write(h) 330 writeString(h, hostKeyBytes) 331 writeString(h, kexECDHInit.ClientPubKey) 332 writeString(h, serializedEphKey) 333 334 K := make([]byte, intLength(secret)) 335 marshalInt(K, secret) 336 h.Write(K) 337 338 H := h.Sum(nil) 339 340 // H is already a hash, but the hostkey signing will apply its 341 // own key-specific hash algorithm. 342 sig, err := signAndMarshal(priv, rand, H) 343 if err != nil { 344 return nil, err 345 } 346 347 reply := kexECDHReplyMsg{ 348 EphemeralPubKey: serializedEphKey, 349 HostKey: hostKeyBytes, 350 Signature: sig, 351 } 352 353 serialized := Marshal(&reply) 354 if err := c.writePacket(serialized); err != nil { 355 return nil, err 356 } 357 358 return &kexResult{ 359 H: H, 360 K: K, 361 HostKey: reply.HostKey, 362 Signature: sig, 363 Hash: ecHash(kex.curve), 364 }, nil 365 } 366 367 var kexAlgoMap = map[string]kexAlgorithm{} 368 369 func init() { 370 // This is the group called diffie-hellman-group1-sha1 in RFC 371 // 4253 and Oakley Group 2 in RFC 2409. 372 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) 373 kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ 374 g: new(big.Int).SetInt64(2), 375 p: p, 376 } 377 378 // This is the group called diffie-hellman-group14-sha1 in RFC 379 // 4253 and Oakley Group 14 in RFC 3526. 380 p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) 381 382 kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ 383 g: new(big.Int).SetInt64(2), 384 p: p, 385 } 386 387 kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} 388 kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} 389 kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} 390 kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} 391 } 392 393 // curve25519sha256 implements the curve25519-sha256@libssh.org key 394 // agreement protocol, as described in 395 // https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt 396 type curve25519sha256 struct{} 397 398 type curve25519KeyPair struct { 399 priv [32]byte 400 pub [32]byte 401 } 402 403 func (kp *curve25519KeyPair) generate(rand io.Reader) error { 404 if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { 405 return err 406 } 407 curve25519.ScalarBaseMult(&kp.pub, &kp.priv) 408 return nil 409 } 410 411 // curve25519Zeros is just an array of 32 zero bytes so that we have something 412 // convenient to compare against in order to reject curve25519 points with the 413 // wrong order. 414 var curve25519Zeros [32]byte 415 416 func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { 417 var kp curve25519KeyPair 418 if err := kp.generate(rand); err != nil { 419 return nil, err 420 } 421 if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { 422 return nil, err 423 } 424 425 packet, err := c.readPacket() 426 if err != nil { 427 return nil, err 428 } 429 430 var reply kexECDHReplyMsg 431 if err = Unmarshal(packet, &reply); err != nil { 432 return nil, err 433 } 434 if len(reply.EphemeralPubKey) != 32 { 435 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 436 } 437 438 var servPub, secret [32]byte 439 copy(servPub[:], reply.EphemeralPubKey) 440 curve25519.ScalarMult(&secret, &kp.priv, &servPub) 441 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 442 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 443 } 444 445 h := crypto.SHA256.New() 446 magics.write(h) 447 writeString(h, reply.HostKey) 448 writeString(h, kp.pub[:]) 449 writeString(h, reply.EphemeralPubKey) 450 451 kInt := new(big.Int).SetBytes(secret[:]) 452 K := make([]byte, intLength(kInt)) 453 marshalInt(K, kInt) 454 h.Write(K) 455 456 return &kexResult{ 457 H: h.Sum(nil), 458 K: K, 459 HostKey: reply.HostKey, 460 Signature: reply.Signature, 461 Hash: crypto.SHA256, 462 }, nil 463 } 464 465 func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { 466 packet, err := c.readPacket() 467 if err != nil { 468 return 469 } 470 var kexInit kexECDHInitMsg 471 if err = Unmarshal(packet, &kexInit); err != nil { 472 return 473 } 474 475 if len(kexInit.ClientPubKey) != 32 { 476 return nil, errors.New("ssh: peer's curve25519 public value has wrong length") 477 } 478 479 var kp curve25519KeyPair 480 if err := kp.generate(rand); err != nil { 481 return nil, err 482 } 483 484 var clientPub, secret [32]byte 485 copy(clientPub[:], kexInit.ClientPubKey) 486 curve25519.ScalarMult(&secret, &kp.priv, &clientPub) 487 if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { 488 return nil, errors.New("ssh: peer's curve25519 public value has wrong order") 489 } 490 491 hostKeyBytes := priv.PublicKey().Marshal() 492 493 h := crypto.SHA256.New() 494 magics.write(h) 495 writeString(h, hostKeyBytes) 496 writeString(h, kexInit.ClientPubKey) 497 writeString(h, kp.pub[:]) 498 499 kInt := new(big.Int).SetBytes(secret[:]) 500 K := make([]byte, intLength(kInt)) 501 marshalInt(K, kInt) 502 h.Write(K) 503 504 H := h.Sum(nil) 505 506 sig, err := signAndMarshal(priv, rand, H) 507 if err != nil { 508 return nil, err 509 } 510 511 reply := kexECDHReplyMsg{ 512 EphemeralPubKey: kp.pub[:], 513 HostKey: hostKeyBytes, 514 Signature: sig, 515 } 516 if err := c.writePacket(Marshal(&reply)); err != nil { 517 return nil, err 518 } 519 return &kexResult{ 520 H: H, 521 K: K, 522 HostKey: hostKeyBytes, 523 Signature: sig, 524 Hash: crypto.SHA256, 525 }, nil 526 }