aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/exp
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-12-14 15:41:54 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-12-14 15:41:54 +0000
commitd5363590597572228d4e0d0ae13f3469176ceb14 (patch)
treee3de46cbc89d82ca1f49843fe2e1e670db67795e /libgo/go/exp
parentef0d4c4d9937276c8ff818ecb0b92925d322d3bd (diff)
downloadgcc-d5363590597572228d4e0d0ae13f3469176ceb14.zip
gcc-d5363590597572228d4e0d0ae13f3469176ceb14.tar.gz
gcc-d5363590597572228d4e0d0ae13f3469176ceb14.tar.bz2
libgo: Update to weekly.2011-12-06.
From-SVN: r182338
Diffstat (limited to 'libgo/go/exp')
-rw-r--r--libgo/go/exp/norm/maketables.go12
-rw-r--r--libgo/go/exp/norm/normregtest.go2
-rw-r--r--libgo/go/exp/sql/convert.go6
-rw-r--r--libgo/go/exp/sql/driver/types.go4
-rw-r--r--libgo/go/exp/ssh/cipher.go10
-rw-r--r--libgo/go/exp/ssh/client.go79
-rw-r--r--libgo/go/exp/ssh/client_auth.go183
-rw-r--r--libgo/go/exp/ssh/client_auth_test.go233
-rw-r--r--libgo/go/exp/ssh/common_test.go16
-rw-r--r--libgo/go/exp/ssh/session.go41
-rw-r--r--libgo/go/exp/ssh/session_test.go2
-rw-r--r--libgo/go/exp/ssh/tcpip.go48
-rw-r--r--libgo/go/exp/types/gcimporter.go14
13 files changed, 337 insertions, 313 deletions
diff --git a/libgo/go/exp/norm/maketables.go b/libgo/go/exp/norm/maketables.go
index 39bab7f..9a97831 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 6610c25..d214ce1 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 48e2812..24315a0 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 6e0ce43..086b529 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 de4926d..d91929a 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 429dee9..d89b908 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 25f9e21..1a38235 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 4ef9213..2b89e97 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 2f4448a..058fb04 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 5f98a8d..23ea18c 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 4be7746..d4818c2 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 f3bbac5..a85044a 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 16a8667..6adcc2a 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()