diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-12-14 15:41:54 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-12-14 15:41:54 +0000 |
commit | 7da93e24295c8b313ecdcedee0b8bde70b335e61 (patch) | |
tree | e3de46cbc89d82ca1f49843fe2e1e670db67795e /libgo/go/exp | |
parent | f86a7907050666ce7cab2890b353619f83d6c98b (diff) | |
download | gcc-7da93e24295c8b313ecdcedee0b8bde70b335e61.tar.gz |
libgo: Update to weekly.2011-12-06.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@182338 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/exp')
-rw-r--r-- | libgo/go/exp/norm/maketables.go | 12 | ||||
-rw-r--r-- | libgo/go/exp/norm/normregtest.go | 2 | ||||
-rw-r--r-- | libgo/go/exp/sql/convert.go | 6 | ||||
-rw-r--r-- | libgo/go/exp/sql/driver/types.go | 4 | ||||
-rw-r--r-- | libgo/go/exp/ssh/cipher.go | 10 | ||||
-rw-r--r-- | libgo/go/exp/ssh/client.go | 79 | ||||
-rw-r--r-- | libgo/go/exp/ssh/client_auth.go | 183 | ||||
-rw-r--r-- | libgo/go/exp/ssh/client_auth_test.go | 233 | ||||
-rw-r--r-- | libgo/go/exp/ssh/common_test.go | 16 | ||||
-rw-r--r-- | libgo/go/exp/ssh/session.go | 41 | ||||
-rw-r--r-- | libgo/go/exp/ssh/session_test.go | 2 | ||||
-rw-r--r-- | libgo/go/exp/ssh/tcpip.go | 48 | ||||
-rw-r--r-- | libgo/go/exp/types/gcimporter.go | 14 |
13 files changed, 337 insertions, 313 deletions
diff --git a/libgo/go/exp/norm/maketables.go b/libgo/go/exp/norm/maketables.go index 39bab7f0b6a..9a97831716b 100644 --- a/libgo/go/exp/norm/maketables.go +++ b/libgo/go/exp/norm/maketables.go @@ -226,7 +226,7 @@ func parseDecomposition(s string, skipfirst bool) (a []rune, e error) { decomp = decomp[1:] } for _, d := range decomp { - point, err := strconv.Btoui64(d, 16) + point, err := strconv.ParseUint(d, 16, 64) if err != nil { return a, err } @@ -240,7 +240,7 @@ func parseCharacter(line string) { if len(field) != NumField { logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField) } - x, err := strconv.Btoui64(field[FCodePoint], 16) + x, err := strconv.ParseUint(field[FCodePoint], 16, 64) point := int(x) if err != nil { logger.Fatalf("%.5s...: %s", line, err) @@ -264,7 +264,7 @@ func parseCharacter(line string) { if state != SLast { firstChar = lastChar } - x, err = strconv.Atoui64(field[FCanonicalCombiningClass]) + x, err = strconv.ParseUint(field[FCanonicalCombiningClass], 10, 64) if err != nil { logger.Fatalf("%U: bad ccc field: %s", int(x), err) } @@ -336,7 +336,7 @@ func parseExclusion(line string) int { if len(matches) != 2 { logger.Fatalf("%s: %d matches (expected 1)\n", line, len(matches)) } - point, err := strconv.Btoui64(matches[1], 16) + point, err := strconv.ParseUint(matches[1], 16, 64) if err != nil { logger.Fatalf("%.5s...: %s", line, err) } @@ -792,13 +792,13 @@ func testDerived() { continue } rng := strings.Split(qc[1], "..") - i, err := strconv.Btoui64(rng[0], 16) + i, err := strconv.ParseUint(rng[0], 16, 64) if err != nil { log.Fatal(err) } j := i if len(rng) > 1 { - j, err = strconv.Btoui64(rng[1], 16) + j, err = strconv.ParseUint(rng[1], 16, 64) if err != nil { log.Fatal(err) } diff --git a/libgo/go/exp/norm/normregtest.go b/libgo/go/exp/norm/normregtest.go index 6610c257e51..d214ce11bc2 100644 --- a/libgo/go/exp/norm/normregtest.go +++ b/libgo/go/exp/norm/normregtest.go @@ -171,7 +171,7 @@ func loadTestData() { counter++ for j := 1; j < len(m)-1; j++ { for _, split := range strings.Split(m[j], " ") { - r, err := strconv.Btoui64(split, 16) + r, err := strconv.ParseUint(split, 16, 64) if err != nil { logger.Fatal(err) } diff --git a/libgo/go/exp/sql/convert.go b/libgo/go/exp/sql/convert.go index 48e281203be..24315a0d351 100644 --- a/libgo/go/exp/sql/convert.go +++ b/libgo/go/exp/sql/convert.go @@ -95,7 +95,7 @@ func convertAssign(dest, src interface{}) error { switch dv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: s := asString(src) - i64, err := strconv.Atoi64(s) + i64, err := strconv.ParseInt(s, 10, 64) if err != nil { return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) } @@ -106,7 +106,7 @@ func convertAssign(dest, src interface{}) error { return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: s := asString(src) - u64, err := strconv.Atoui64(s) + u64, err := strconv.ParseUint(s, 10, 64) if err != nil { return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) } @@ -117,7 +117,7 @@ func convertAssign(dest, src interface{}) error { return nil case reflect.Float32, reflect.Float64: s := asString(src) - f64, err := strconv.Atof64(s) + f64, err := strconv.ParseFloat(s, 64) if err != nil { return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) } diff --git a/libgo/go/exp/sql/driver/types.go b/libgo/go/exp/sql/driver/types.go index 6e0ce4339cc..086b529c84f 100644 --- a/libgo/go/exp/sql/driver/types.go +++ b/libgo/go/exp/sql/driver/types.go @@ -54,13 +54,13 @@ func (boolType) ConvertValue(src interface{}) (interface{}, error) { case bool: return s, nil case string: - b, err := strconv.Atob(s) + b, err := strconv.ParseBool(s) if err != nil { return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) } return b, nil case []byte: - b, err := strconv.Atob(string(s)) + b, err := strconv.ParseBool(string(s)) if err != nil { return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) } diff --git a/libgo/go/exp/ssh/cipher.go b/libgo/go/exp/ssh/cipher.go index de4926d7b81..d91929aa99a 100644 --- a/libgo/go/exp/ssh/cipher.go +++ b/libgo/go/exp/ssh/cipher.go @@ -77,12 +77,12 @@ var DefaultCipherOrder = []string{ var cipherModes = map[string]*cipherMode{ // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms // are defined in the order specified in the RFC. - "aes128-ctr": &cipherMode{16, aes.BlockSize, 0, newAESCTR}, - "aes192-ctr": &cipherMode{24, aes.BlockSize, 0, newAESCTR}, - "aes256-ctr": &cipherMode{32, aes.BlockSize, 0, newAESCTR}, + "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, + "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, + "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. // They are defined in the order specified in the RFC. - "arcfour128": &cipherMode{16, 0, 1536, newRC4}, - "arcfour256": &cipherMode{32, 0, 1536, newRC4}, + "arcfour128": {16, 0, 1536, newRC4}, + "arcfour256": {32, 0, 1536, newRC4}, } diff --git a/libgo/go/exp/ssh/client.go b/libgo/go/exp/ssh/client.go index 429dee975bc..d89b908cdcf 100644 --- a/libgo/go/exp/ssh/client.go +++ b/libgo/go/exp/ssh/client.go @@ -200,7 +200,7 @@ func (c *ClientConn) mainLoop() { peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4]) if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 { packet = packet[9:] - c.getChan(peersId).data <- packet[:length] + c.getChan(peersId).stdout.data <- packet[:length] } case msgChannelExtendedData: if len(packet) < 13 { @@ -215,7 +215,7 @@ func (c *ClientConn) mainLoop() { // for stderr on interactive sessions. Other data types are // silently discarded. if datatype == 1 { - c.getChan(peersId).dataExt <- packet[:length] + c.getChan(peersId).stderr.data <- packet[:length] } } default: @@ -228,9 +228,9 @@ func (c *ClientConn) mainLoop() { c.getChan(msg.PeersId).msg <- msg case *channelCloseMsg: ch := c.getChan(msg.PeersId) - close(ch.win) - close(ch.data) - close(ch.dataExt) + close(ch.stdin.win) + close(ch.stdout.data) + close(ch.stderr.data) c.chanlist.remove(msg.PeersId) case *channelEOFMsg: c.getChan(msg.PeersId).msg <- msg @@ -241,7 +241,7 @@ func (c *ClientConn) mainLoop() { case *channelRequestMsg: c.getChan(msg.PeersId).msg <- msg case *windowAdjustMsg: - c.getChan(msg.PeersId).win <- int(msg.AdditionalBytes) + c.getChan(msg.PeersId).stdin.win <- int(msg.AdditionalBytes) default: fmt.Printf("mainLoop: unhandled message %T: %v\n", msg, msg) } @@ -290,21 +290,49 @@ func (c *ClientConfig) rand() io.Reader { type clientChan struct { packetWriter id, peersId uint32 - data chan []byte // receives the payload of channelData messages - dataExt chan []byte // receives the payload of channelExtendedData messages - win chan int // receives window adjustments + stdin *chanWriter // receives window adjustments + stdout *chanReader // receives the payload of channelData messages + stderr *chanReader // receives the payload of channelExtendedData messages msg chan interface{} // incoming messages } +// newClientChan returns a partially constructed *clientChan +// using the local id provided. To be usable clientChan.peersId +// needs to be assigned once known. func newClientChan(t *transport, id uint32) *clientChan { - return &clientChan{ + c := &clientChan{ packetWriter: t, id: id, - data: make(chan []byte, 16), - dataExt: make(chan []byte, 16), - win: make(chan int, 16), msg: make(chan interface{}, 16), } + c.stdin = &chanWriter{ + win: make(chan int, 16), + clientChan: c, + } + c.stdout = &chanReader{ + data: make(chan []byte, 16), + clientChan: c, + } + c.stderr = &chanReader{ + data: make(chan []byte, 16), + clientChan: c, + } + return c +} + +// waitForChannelOpenResponse, if successful, fills out +// the peerId and records any initial window advertisement. +func (c *clientChan) waitForChannelOpenResponse() error { + switch msg := (<-c.msg).(type) { + case *channelOpenConfirmMsg: + // fixup peersId field + c.peersId = msg.MyId + c.stdin.win <- int(msg.MyWindow) + return nil + case *channelOpenFailureMsg: + return errors.New(safeString(msg.Message)) + } + return errors.New("unexpected packet") } // Close closes the channel. This does not close the underlying connection. @@ -355,10 +383,9 @@ func (c *chanlist) remove(id uint32) { // A chanWriter represents the stdin of a remote process. type chanWriter struct { - win chan int // receives window adjustments - peersId uint32 // the peer's id - rwin int // current rwin size - packetWriter // for sending channelDataMsg + win chan int // receives window adjustments + rwin int // current rwin size + clientChan *clientChan // the channel backing this writer } // Write writes data to the remote process's standard input. @@ -372,12 +399,13 @@ func (w *chanWriter) Write(data []byte) (n int, err error) { w.rwin += win continue } + peersId := w.clientChan.peersId n = len(data) packet := make([]byte, 0, 9+n) packet = append(packet, msgChannelData, - byte(w.peersId>>24), byte(w.peersId>>16), byte(w.peersId>>8), byte(w.peersId), + byte(peersId>>24), byte(peersId>>16), byte(peersId>>8), byte(peersId), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) - err = w.writePacket(append(packet, data...)) + err = w.clientChan.writePacket(append(packet, data...)) w.rwin -= n return } @@ -385,7 +413,7 @@ func (w *chanWriter) Write(data []byte) (n int, err error) { } func (w *chanWriter) Close() error { - return w.writePacket(marshal(msgChannelEOF, channelEOFMsg{w.peersId})) + return w.clientChan.writePacket(marshal(msgChannelEOF, channelEOFMsg{w.clientChan.peersId})) } // A chanReader represents stdout or stderr of a remote process. @@ -393,10 +421,9 @@ type chanReader struct { // TODO(dfc) a fixed size channel may not be the right data structure. // If writes to this channel block, they will block mainLoop, making // it unable to receive new messages from the remote side. - data chan []byte // receives data from remote - peersId uint32 // the peer's id - packetWriter // for sending windowAdjustMsg - buf []byte + data chan []byte // receives data from remote + clientChan *clientChan // the channel backing this reader + buf []byte } // Read reads data from the remote process's stdout or stderr. @@ -407,10 +434,10 @@ func (r *chanReader) Read(data []byte) (int, error) { n := copy(data, r.buf) r.buf = r.buf[n:] msg := windowAdjustMsg{ - PeersId: r.peersId, + PeersId: r.clientChan.peersId, AdditionalBytes: uint32(n), } - return n, r.writePacket(marshal(msgChannelWindowAdjust, msg)) + return n, r.clientChan.writePacket(marshal(msgChannelWindowAdjust, msg)) } r.buf, ok = <-r.data if !ok { diff --git a/libgo/go/exp/ssh/client_auth.go b/libgo/go/exp/ssh/client_auth.go index 25f9e216225..1a382357b46 100644 --- a/libgo/go/exp/ssh/client_auth.go +++ b/libgo/go/exp/ssh/client_auth.go @@ -9,7 +9,7 @@ import ( "io" ) -// authenticate authenticates with the remote server. See RFC 4252. +// authenticate authenticates with the remote server. See RFC 4252. func (c *ClientConn) authenticate(session []byte) error { // initiate user auth session if err := c.writePacket(marshal(msgServiceRequest, serviceRequestMsg{serviceUserAuth})); err != nil { @@ -24,7 +24,7 @@ func (c *ClientConn) authenticate(session []byte) error { return err } // during the authentication phase the client first attempts the "none" method - // then any untried methods suggested by the server. + // then any untried methods suggested by the server. tried, remain := make(map[string]bool), make(map[string]bool) for auth := ClientAuth(new(noneAuth)); auth != nil; { ok, methods, err := auth.auth(session, c.config.User, c.transport, c.config.rand()) @@ -57,9 +57,9 @@ func (c *ClientConn) authenticate(session []byte) error { // A ClientAuth represents an instance of an RFC 4252 authentication method. type ClientAuth interface { - // auth authenticates user over transport t. + // auth authenticates user over transport t. // Returns true if authentication is successful. - // If authentication is not successful, a []string of alternative + // If authentication is not successful, a []string of alternative // method names is returned. auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) @@ -79,19 +79,7 @@ func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reade return false, nil, err } - packet, err := t.readPacket() - if err != nil { - return false, nil, err - } - - switch packet[0] { - case msgUserAuthSuccess: - return true, nil, nil - case msgUserAuthFailure: - msg := decode(packet).(*userAuthFailureMsg) - return false, msg.Methods, nil - } - return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} + return handleAuthResponse(t) } func (n *noneAuth) method() string { @@ -127,19 +115,7 @@ func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.R return false, nil, err } - packet, err := t.readPacket() - if err != nil { - return false, nil, err - } - - switch packet[0] { - case msgUserAuthSuccess: - return true, nil, nil - case msgUserAuthFailure: - msg := decode(packet).(*userAuthFailureMsg) - return false, msg.Methods, nil - } - return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} + return handleAuthResponse(t) } func (p *passwordAuth) method() string { @@ -159,7 +135,7 @@ func ClientAuthPassword(impl ClientPassword) ClientAuth { // ClientKeyring implements access to a client key ring. type ClientKeyring interface { - // Key returns the i'th rsa.Publickey or dsa.Publickey, or nil if + // Key returns the i'th rsa.Publickey or dsa.Publickey, or nil if // no key exists at i. Key(i int) (key interface{}, err error) @@ -173,27 +149,28 @@ type publickeyAuth struct { ClientKeyring } +type publickeyAuthMsg struct { + User string + Service string + Method string + // HasSig indicates to the reciver packet that the auth request is signed and + // should be used for authentication of the request. + HasSig bool + Algoname string + Pubkey string + // Sig is defined as []byte so marshal will exclude it during validateKey + Sig []byte `ssh:"rest"` +} + func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { - type publickeyAuthMsg struct { - User string - Service string - Method string - // HasSig indicates to the reciver packet that the auth request is signed and - // should be used for authentication of the request. - HasSig bool - Algoname string - Pubkey string - // Sig is defined as []byte so marshal will exclude it during the query phase - Sig []byte `ssh:"rest"` - } // Authentication is performed in two stages. The first stage sends an // enquiry to test if each key is acceptable to the remote. The second - // stage attempts to authenticate with the valid keys obtained in the + // stage attempts to authenticate with the valid keys obtained in the // first stage. var index int - // a map of public keys to their index in the keyring + // a map of public keys to their index in the keyring validKeys := make(map[int]interface{}) for { key, err := p.Key(index) @@ -204,33 +181,13 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io. // no more keys in the keyring break } - pubkey := serializePublickey(key) - algoname := algoName(key) - msg := publickeyAuthMsg{ - User: user, - Service: serviceSSH, - Method: p.method(), - HasSig: false, - Algoname: algoname, - Pubkey: string(pubkey), - } - if err := t.writePacket(marshal(msgUserAuthRequest, msg)); err != nil { - return false, nil, err - } - packet, err := t.readPacket() - if err != nil { - return false, nil, err - } - switch packet[0] { - case msgUserAuthPubKeyOk: - msg := decode(packet).(*userAuthPubKeyOkMsg) - if msg.Algo != algoname || msg.PubKey != string(pubkey) { - continue - } + + if ok, err := p.validateKey(key, user, t); ok { validKeys[index] = key - case msgUserAuthFailure: - default: - return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} + } else { + if err != nil { + return false, nil, err + } } index++ } @@ -265,24 +222,61 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io. if err := t.writePacket(p); err != nil { return false, nil, err } - packet, err := t.readPacket() + success, methods, err := handleAuthResponse(t) if err != nil { return false, nil, err } + if success { + return success, methods, err + } + } + return false, methods, nil +} + +// validateKey validates the key provided it is acceptable to the server. +func (p *publickeyAuth) validateKey(key interface{}, user string, t *transport) (bool, error) { + pubkey := serializePublickey(key) + algoname := algoName(key) + msg := publickeyAuthMsg{ + User: user, + Service: serviceSSH, + Method: p.method(), + HasSig: false, + Algoname: algoname, + Pubkey: string(pubkey), + } + if err := t.writePacket(marshal(msgUserAuthRequest, msg)); err != nil { + return false, err + } + + return p.confirmKeyAck(key, t) +} + +func (p *publickeyAuth) confirmKeyAck(key interface{}, t *transport) (bool, error) { + pubkey := serializePublickey(key) + algoname := algoName(key) + + for { + packet, err := t.readPacket() + if err != nil { + return false, err + } switch packet[0] { - case msgUserAuthSuccess: - return true, nil, nil + case msgUserAuthBanner: + // TODO(gpaul): add callback to present the banner to the user + case msgUserAuthPubKeyOk: + msg := decode(packet).(*userAuthPubKeyOkMsg) + if msg.Algo != algoname || msg.PubKey != string(pubkey) { + return false, nil + } + return true, nil case msgUserAuthFailure: - msg := decode(packet).(*userAuthFailureMsg) - methods = msg.Methods - continue - case msgDisconnect: - return false, nil, io.EOF + return false, nil default: - return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} + return false, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} } } - return false, methods, nil + panic("unreachable") } func (p *publickeyAuth) method() string { @@ -293,3 +287,30 @@ func (p *publickeyAuth) method() string { func ClientAuthPublickey(impl ClientKeyring) ClientAuth { return &publickeyAuth{impl} } + +// handleAuthResponse returns whether the preceding authentication request succeeded +// along with a list of remaining authentication methods to try next and +// an error if an unexpected response was received. +func handleAuthResponse(t *transport) (bool, []string, error) { + for { + packet, err := t.readPacket() + if err != nil { + return false, nil, err + } + + switch packet[0] { + case msgUserAuthBanner: + // TODO: add callback to present the banner to the user + case msgUserAuthFailure: + msg := decode(packet).(*userAuthFailureMsg) + return false, msg.Methods, nil + case msgUserAuthSuccess: + return true, nil, nil + case msgDisconnect: + return false, nil, io.EOF + default: + return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]} + } + } + panic("unreachable") +} diff --git a/libgo/go/exp/ssh/client_auth_test.go b/libgo/go/exp/ssh/client_auth_test.go index 4ef9213a9cd..2b89e9728c7 100644 --- a/libgo/go/exp/ssh/client_auth_test.go +++ b/libgo/go/exp/ssh/client_auth_test.go @@ -7,17 +7,20 @@ package ssh import ( "bytes" "crypto" - "crypto/rand" + "crypto/dsa" "crypto/rsa" + _ "crypto/sha1" "crypto/x509" "encoding/pem" "errors" "io" "io/ioutil" + "math/big" "testing" ) -const _pem = `-----BEGIN RSA PRIVATE KEY----- +// private key for mock server +const testServerPrivateKey = `-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU 70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx 9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF @@ -45,25 +48,32 @@ gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw== -----END RSA PRIVATE KEY-----` -// reused internally by tests -var serverConfig = new(ServerConfig) - -func init() { - if err := serverConfig.SetRSAPrivateKey([]byte(_pem)); err != nil { - panic("unable to set private key: " + err.Error()) - } -} +const testClientPrivateKey = `-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBALdGZxkXDAjsYk10ihwU6Id2KeILz1TAJuoq4tOgDWxEEGeTrcld +r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ +tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC +nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW +2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB +y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr +rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg== +-----END RSA PRIVATE KEY-----` // keychain implements the ClientPublickey interface type keychain struct { - keys []*rsa.PrivateKey + keys []interface{} } func (k *keychain) Key(i int) (interface{}, error) { if i < 0 || i >= len(k.keys) { return nil, nil } - return k.keys[i].PublicKey, nil + switch key := k.keys[i].(type) { + case *rsa.PrivateKey: + return key.PublicKey, nil + case *dsa.PrivateKey: + return key.PublicKey, nil + } + panic("unknown key type") } func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) { @@ -71,7 +81,11 @@ func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err err h := hashFunc.New() h.Write(data) digest := h.Sum(nil) - return rsa.SignPKCS1v15(rand, k.keys[i], hashFunc, digest) + switch key := k.keys[i].(type) { + case *rsa.PrivateKey: + return rsa.SignPKCS1v15(rand, key, hashFunc, digest) + } + return nil, errors.New("unknown key type") } func (k *keychain) loadPEM(file string) error { @@ -91,158 +105,153 @@ func (k *keychain) loadPEM(file string) error { return nil } -var pkey *rsa.PrivateKey +// password implements the ClientPassword interface +type password string -func init() { - var err error - pkey, err = rsa.GenerateKey(rand.Reader, 512) - if err != nil { - panic("unable to generate public key") - } +func (p password) Password(user string) (string, error) { + return string(p), nil } -func TestClientAuthPublickey(t *testing.T) { - k := new(keychain) - k.keys = append(k.keys, pkey) +// reused internally by tests +var ( + rsakey *rsa.PrivateKey + dsakey *dsa.PrivateKey + clientKeychain = new(keychain) + clientPassword = password("tiger") + serverConfig = &ServerConfig{ + PasswordCallback: func(user, pass string) bool { + return user == "testuser" && pass == string(clientPassword) + }, + PubKeyCallback: func(user, algo string, pubkey []byte) bool { + key := clientKeychain.keys[0].(*rsa.PrivateKey).PublicKey + expected := []byte(serializePublickey(key)) + algoname := algoName(key) + return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected) + }, + } +) - serverConfig.PubKeyCallback = func(user, algo string, pubkey []byte) bool { - expected := []byte(serializePublickey(k.keys[0].PublicKey)) - algoname := algoName(k.keys[0].PublicKey) - return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected) +func init() { + if err := serverConfig.SetRSAPrivateKey([]byte(testServerPrivateKey)); err != nil { + panic("unable to set private key: " + err.Error()) } - serverConfig.PasswordCallback = nil + block, _ := pem.Decode([]byte(testClientPrivateKey)) + rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes) + + clientKeychain.keys = append(clientKeychain.keys, rsakey) + dsakey = new(dsa.PrivateKey) + // taken from crypto/dsa/dsa_test.go + dsakey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16) + dsakey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16) + dsakey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16) + dsakey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16) + dsakey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16) +} + +// newMockAuthServer creates a new Server bound to +// the loopback interface. The server exits after +// processing one handshake. +func newMockAuthServer(t *testing.T) string { l, err := Listen("tcp", "127.0.0.1:0", serverConfig) if err != nil { - t.Fatalf("unable to listen: %s", err) + t.Fatalf("unable to newMockAuthServer: %s", err) } - defer l.Close() - - done := make(chan bool, 1) go func() { + defer l.Close() c, err := l.Accept() + defer c.Close() if err != nil { - t.Fatal(err) + t.Errorf("Unable to accept incoming connection: %v", err) + return } - defer c.Close() if err := c.Handshake(); err != nil { - t.Error(err) + // not Errorf because this is expected to + // fail for some tests. + t.Logf("Handshaking error: %v", err) + return } - done <- true }() + return l.Addr().String() +} +func TestClientAuthPublickey(t *testing.T) { config := &ClientConfig{ User: "testuser", Auth: []ClientAuth{ - ClientAuthPublickey(k), + ClientAuthPublickey(clientKeychain), }, } - - c, err := Dial("tcp", l.Addr().String(), config) + c, err := Dial("tcp", newMockAuthServer(t), config) if err != nil { t.Fatalf("unable to dial remote side: %s", err) } - defer c.Close() - <-done -} - -// password implements the ClientPassword interface -type password string - -func (p password) Password(user string) (string, error) { - return string(p), nil + c.Close() } func TestClientAuthPassword(t *testing.T) { - pw := password("tiger") - - serverConfig.PasswordCallback = func(user, pass string) bool { - return user == "testuser" && pass == string(pw) + config := &ClientConfig{ + User: "testuser", + Auth: []ClientAuth{ + ClientAuthPassword(clientPassword), + }, } - serverConfig.PubKeyCallback = nil - l, err := Listen("tcp", "127.0.0.1:0", serverConfig) + c, err := Dial("tcp", newMockAuthServer(t), config) if err != nil { - t.Fatalf("unable to listen: %s", err) + t.Fatalf("unable to dial remote side: %s", err) } - defer l.Close() - - done := make(chan bool) - go func() { - c, err := l.Accept() - if err != nil { - t.Fatal(err) - } - if err := c.Handshake(); err != nil { - t.Error(err) - } - defer c.Close() - done <- true - }() + c.Close() +} +func TestClientAuthWrongPassword(t *testing.T) { + wrongPw := password("wrong") config := &ClientConfig{ User: "testuser", Auth: []ClientAuth{ - ClientAuthPassword(pw), + ClientAuthPassword(wrongPw), + ClientAuthPublickey(clientKeychain), }, } - c, err := Dial("tcp", l.Addr().String(), config) + c, err := Dial("tcp", newMockAuthServer(t), config) if err != nil { t.Fatalf("unable to dial remote side: %s", err) } - defer c.Close() - <-done + c.Close() } -func TestClientAuthPasswordAndPublickey(t *testing.T) { - pw := password("tiger") - - serverConfig.PasswordCallback = func(user, pass string) bool { - return user == "testuser" && pass == string(pw) - } - - k := new(keychain) - k.keys = append(k.keys, pkey) - - serverConfig.PubKeyCallback = func(user, algo string, pubkey []byte) bool { - expected := []byte(serializePublickey(k.keys[0].PublicKey)) - algoname := algoName(k.keys[0].PublicKey) - return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected) +// the mock server will only authenticate ssh-rsa keys +func TestClientAuthInvalidPublickey(t *testing.T) { + kc := new(keychain) + kc.keys = append(kc.keys, dsakey) + config := &ClientConfig{ + User: "testuser", + Auth: []ClientAuth{ + ClientAuthPublickey(kc), + }, } - l, err := Listen("tcp", "127.0.0.1:0", serverConfig) - if err != nil { - t.Fatalf("unable to listen: %s", err) + c, err := Dial("tcp", newMockAuthServer(t), config) + if err == nil { + c.Close() + t.Fatalf("dsa private key should not have authenticated with rsa public key") } - defer l.Close() - - done := make(chan bool) - go func() { - c, err := l.Accept() - if err != nil { - t.Fatal(err) - } - if err := c.Handshake(); err != nil { - t.Error(err) - } - defer c.Close() - done <- true - }() +} - wrongPw := password("wrong") +// the client should authenticate with the second key +func TestClientAuthRSAandDSA(t *testing.T) { + kc := new(keychain) + kc.keys = append(kc.keys, dsakey, rsakey) config := &ClientConfig{ User: "testuser", Auth: []ClientAuth{ - ClientAuthPassword(wrongPw), - ClientAuthPublickey(k), + ClientAuthPublickey(kc), }, } - - c, err := Dial("tcp", l.Addr().String(), config) + c, err := Dial("tcp", newMockAuthServer(t), config) if err != nil { - t.Fatalf("unable to dial remote side: %s", err) + t.Fatalf("client could not authenticate with rsa key: %v", err) } - defer c.Close() - <-done + c.Close() } diff --git a/libgo/go/exp/ssh/common_test.go b/libgo/go/exp/ssh/common_test.go index 2f4448a1bd4..058fb04fe1b 100644 --- a/libgo/go/exp/ssh/common_test.go +++ b/libgo/go/exp/ssh/common_test.go @@ -8,15 +8,15 @@ import ( "testing" ) -var strings = map[string]string{ - "\x20\x0d\x0a": "\x20\x0d\x0a", - "flibble": "flibble", - "new\x20line": "new\x20line", - "123456\x07789": "123456 789", - "\t\t\x10\r\n": "\t\t \r\n", -} - func TestSafeString(t *testing.T) { + strings := map[string]string{ + "\x20\x0d\x0a": "\x20\x0d\x0a", + "flibble": "flibble", + "new\x20line": "new\x20line", + "123456\x07789": "123456 789", + "\t\t\x10\r\n": "\t\t \r\n", + } + for s, expected := range strings { actual := safeString(s) if expected != actual { diff --git a/libgo/go/exp/ssh/session.go b/libgo/go/exp/ssh/session.go index 5f98a8d58c6..23ea18c29ae 100644 --- a/libgo/go/exp/ssh/session.go +++ b/libgo/go/exp/ssh/session.go @@ -285,13 +285,8 @@ func (s *Session) stdin() error { s.Stdin = new(bytes.Buffer) } s.copyFuncs = append(s.copyFuncs, func() error { - w := &chanWriter{ - packetWriter: s, - peersId: s.peersId, - win: s.win, - } - _, err := io.Copy(w, s.Stdin) - if err1 := w.Close(); err == nil { + _, err := io.Copy(s.clientChan.stdin, s.Stdin) + if err1 := s.clientChan.stdin.Close(); err == nil { err = err1 } return err @@ -304,12 +299,7 @@ func (s *Session) stdout() error { s.Stdout = ioutil.Discard } s.copyFuncs = append(s.copyFuncs, func() error { - r := &chanReader{ - packetWriter: s, - peersId: s.peersId, - data: s.data, - } - _, err := io.Copy(s.Stdout, r) + _, err := io.Copy(s.Stdout, s.clientChan.stdout) return err }) return nil @@ -320,12 +310,7 @@ func (s *Session) stderr() error { s.Stderr = ioutil.Discard } s.copyFuncs = append(s.copyFuncs, func() error { - r := &chanReader{ - packetWriter: s, - peersId: s.peersId, - data: s.dataExt, - } - _, err := io.Copy(s.Stderr, r) + _, err := io.Copy(s.Stderr, s.clientChan.stderr) return err }) return nil @@ -398,19 +383,11 @@ func (c *ClientConn) NewSession() (*Session, error) { c.chanlist.remove(ch.id) return nil, err } - // wait for response - msg := <-ch.msg - switch msg := msg.(type) { - case *channelOpenConfirmMsg: - ch.peersId = msg.MyId - ch.win <- int(msg.MyWindow) - return &Session{ - clientChan: ch, - }, nil - case *channelOpenFailureMsg: + if err := ch.waitForChannelOpenResponse(); err != nil { c.chanlist.remove(ch.id) - return nil, fmt.Errorf("ssh: channel open failed: %s", msg.Message) + return nil, fmt.Errorf("ssh: unable to open session: %v", err) } - c.chanlist.remove(ch.id) - return nil, fmt.Errorf("ssh: unexpected message %T: %v", msg, msg) + return &Session{ + clientChan: ch, + }, nil } diff --git a/libgo/go/exp/ssh/session_test.go b/libgo/go/exp/ssh/session_test.go index 4be7746d17e..d4818c29f70 100644 --- a/libgo/go/exp/ssh/session_test.go +++ b/libgo/go/exp/ssh/session_test.go @@ -61,7 +61,7 @@ func dial(t *testing.T) *ClientConn { WantReply bool Status uint32 } - // TODO(dfc) casting to the concrete type should not be + // TODO(dfc) converting to the concrete type should not be // necessary to send a packet. msg := exitMsg{ PeersId: ch.(*channel).theirId, diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go index f3bbac5d19e..a85044ace9c 100644 --- a/libgo/go/exp/ssh/tcpip.go +++ b/libgo/go/exp/ssh/tcpip.go @@ -6,6 +6,7 @@ package ssh import ( "errors" + "fmt" "io" "net" ) @@ -42,20 +43,21 @@ func (c *ClientConn) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, err }, nil } +// RFC 4254 7.2 +type channelOpenDirectMsg struct { + ChanType string + PeersId uint32 + PeersWindow uint32 + MaxPacketSize uint32 + raddr string + rport uint32 + laddr string + lport uint32 +} + // dial opens a direct-tcpip connection to the remote server. laddr and raddr are passed as // strings and are expected to be resolveable at the remote end. func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*tcpchan, error) { - // RFC 4254 7.2 - type channelOpenDirectMsg struct { - ChanType string - PeersId uint32 - PeersWindow uint32 - MaxPacketSize uint32 - raddr string - rport uint32 - laddr string - lport uint32 - } ch := c.newChan(c.transport) if err := c.writePacket(marshal(msgChannelOpen, channelOpenDirectMsg{ ChanType: "direct-tcpip", @@ -70,30 +72,14 @@ func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*tc c.chanlist.remove(ch.id) return nil, err } - // wait for response - switch msg := (<-ch.msg).(type) { - case *channelOpenConfirmMsg: - ch.peersId = msg.MyId - ch.win <- int(msg.MyWindow) - case *channelOpenFailureMsg: - c.chanlist.remove(ch.id) - return nil, errors.New("ssh: error opening remote TCP connection: " + msg.Message) - default: + if err := ch.waitForChannelOpenResponse(); err != nil { c.chanlist.remove(ch.id) - return nil, errors.New("ssh: unexpected packet") + return nil, fmt.Errorf("ssh: unable to open direct tcpip connection: %v", err) } return &tcpchan{ clientChan: ch, - Reader: &chanReader{ - packetWriter: ch, - peersId: ch.peersId, - data: ch.data, - }, - Writer: &chanWriter{ - packetWriter: ch, - peersId: ch.peersId, - win: ch.win, - }, + Reader: ch.stdout, + Writer: ch.stdin, }, nil } diff --git a/libgo/go/exp/types/gcimporter.go b/libgo/go/exp/types/gcimporter.go index 16a8667ff66..6adcc2a9ad2 100644 --- a/libgo/go/exp/types/gcimporter.go +++ b/libgo/go/exp/types/gcimporter.go @@ -305,7 +305,7 @@ func (p *gcParser) parseArrayType() Type { lit := p.expect(scanner.Int) p.expect(']') elt := p.parseType() - n, err := strconv.Atoui64(lit) + n, err := strconv.ParseUint(lit, 10, 64) if err != nil { p.error(err) } @@ -323,7 +323,7 @@ func (p *gcParser) parseMapType() Type { return &Map{Key: key, Elt: elt} } -// Name = identifier | "?" . +// Name = identifier | "?" | ExportedName . // func (p *gcParser) parseName() (name string) { switch p.tok { @@ -333,6 +333,9 @@ func (p *gcParser) parseName() (name string) { case '?': // anonymous p.next() + case '@': + // exported name prefixed with package path + _, name = p.parseExportedName() default: p.error("name expected") } @@ -619,10 +622,11 @@ func (p *gcParser) parseNumber() Const { // exponent (base 2) p.next() sign, val = p.parseInt() - exp, err := strconv.Atoui(val) + exp64, err := strconv.ParseUint(val, 10, 0) if err != nil { p.error(err) } + exp := uint(exp64) if sign == "-" { denom := big.NewInt(1) denom.Lsh(denom, exp) @@ -747,7 +751,7 @@ func (p *gcParser) parseFuncDecl() { } } -// MethodDecl = "func" Receiver identifier Signature . +// MethodDecl = "func" Receiver Name Signature . // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ]. // func (p *gcParser) parseMethodDecl() { @@ -755,7 +759,7 @@ func (p *gcParser) parseMethodDecl() { p.expect('(') p.parseParameter() // receiver p.expect(')') - p.expect(scanner.Ident) + p.parseName() // unexported method names in imports are qualified with their package. p.parseSignature() if p.tok == '{' { p.parseFuncBody() |