Merge "Add a verify method to security.Signature. This is in preparation for adding additional fields so we can support multiple signature encodings."
diff --git a/runtimes/google/ipc/stream/vc/auth.go b/runtimes/google/ipc/stream/vc/auth.go
index 0d4b094..76e7118 100644
--- a/runtimes/google/ipc/stream/vc/auth.go
+++ b/runtimes/google/ipc/stream/vc/auth.go
@@ -11,6 +11,7 @@
 	"veyron/runtimes/google/ipc/stream/crypto"
 	"veyron/runtimes/google/lib/iobuf"
 
+	"veyron2/ipc/version"
 	"veyron2/security"
 	"veyron2/vom"
 )
@@ -22,17 +23,17 @@
 
 // authenticateAsServer executes the authentication protocol at the server and
 // returns the identity of the client and server.
-func authenticateAsServer(conn io.ReadWriteCloser, localID LocalID, crypter crypto.Crypter) (clientID, serverID security.PublicID, err error) {
+func authenticateAsServer(conn io.ReadWriteCloser, localID LocalID, crypter crypto.Crypter, v version.IPCVersion) (clientID, serverID security.PublicID, err error) {
 	// The authentication protocol has the server doing the final read, so
 	// it is the one that closes the connection.
 	defer conn.Close()
 	if serverID, err = localID.AsServer(); err != nil {
 		return
 	}
-	if err = writeIdentity(conn, serverChannelEnd, crypter, localID, serverID); err != nil {
+	if err = writeIdentity(conn, serverChannelEnd, crypter, localID, serverID, v); err != nil {
 		return
 	}
-	clientID, err = readIdentity(conn, clientChannelEnd, crypter)
+	clientID, err = readIdentity(conn, clientChannelEnd, crypter, v)
 	return
 }
 
@@ -41,9 +42,9 @@
 //
 // If serverName is non-nil, the authentication protocol will be considered
 // successfull iff the server identity matches the provided regular expression.
-func authenticateAsClient(conn io.ReadWriteCloser, localID LocalID, crypter crypto.Crypter) (serverID, clientID security.PublicID, err error) {
+func authenticateAsClient(conn io.ReadWriteCloser, localID LocalID, crypter crypto.Crypter, v version.IPCVersion) (serverID, clientID security.PublicID, err error) {
 	defer conn.Close()
-	if serverID, err = readIdentity(conn, serverChannelEnd, crypter); err != nil {
+	if serverID, err = readIdentity(conn, serverChannelEnd, crypter, v); err != nil {
 		return
 	}
 	// TODO(ashankar,ataly): Have the ability to avoid talking to a server we do not want to.
@@ -51,7 +52,7 @@
 	if clientID, err = localID.AsClient(serverID); err != nil {
 		return
 	}
-	err = writeIdentity(conn, clientChannelEnd, crypter, localID, clientID)
+	err = writeIdentity(conn, clientChannelEnd, crypter, localID, clientID, v)
 	return
 }
 
@@ -60,9 +61,11 @@
 //
 // Each field in the message is encrypted by the sender.
 type identityMessage struct {
-	ChannelID    []byte
-	ID           []byte // VOM-encoded
-	SignR, SignS []byte
+	ChannelID []byte
+	ID        []byte // VOM-encoded
+	SignR     []byte
+	SignS     []byte
+	Signature []byte // VOM-encoded
 }
 
 var (
@@ -73,7 +76,7 @@
 	errSingleCertificateRequired = errors.New("exactly one X.509 certificate chain with exactly one certificate is required")
 )
 
-func writeIdentity(w io.Writer, chEnd string, enc crypto.Encrypter, id LocalID, pub security.PublicID) error {
+func writeIdentity(w io.Writer, chEnd string, enc crypto.Encrypter, id LocalID, pub security.PublicID, v version.IPCVersion) error {
 	// Compute channel id - encrypted chEnd string
 	chid, err := enc.Encrypt(iobuf.NewSlice([]byte(chEnd)))
 	if err != nil {
@@ -97,27 +100,40 @@
 	if err != nil {
 		return err
 	}
-	er, err := enc.Encrypt(iobuf.NewSlice(signature.R.Bytes()))
-	if err != nil {
-		return err
-	}
-	defer er.Release()
-	es, err := enc.Encrypt(iobuf.NewSlice(signature.S.Bytes()))
-	if err != nil {
-		return err
-	}
-	defer es.Release()
-
-	// Write the message out.
-	return vom.NewEncoder(w).Encode(identityMessage{
+	msg := identityMessage{
 		ID:        eid.Contents,
 		ChannelID: chid.Contents,
-		SignR:     er.Contents,
-		SignS:     es.Contents,
-	})
+	}
+	if v == version.IPCVersion1 {
+		er, err := enc.Encrypt(iobuf.NewSlice(signature.R))
+		if err != nil {
+			return err
+		}
+		defer er.Release()
+		es, err := enc.Encrypt(iobuf.NewSlice(signature.S))
+		if err != nil {
+			return err
+		}
+		defer es.Release()
+		msg.SignR, msg.SignS = er.Contents, es.Contents
+	} else {
+		buf = bytes.Buffer{}
+		if err := vom.NewEncoder(&buf).Encode(signature); err != nil {
+			return err
+		}
+		esig, err := enc.Encrypt(iobuf.NewSlice(buf.Bytes()))
+		if err != nil {
+			return err
+		}
+		defer esig.Release()
+		msg.Signature = esig.Contents
+	}
+
+	// Write the message out.
+	return vom.NewEncoder(w).Encode(msg)
 }
 
-func readIdentity(reader io.Reader, expectedChEnd string, dec crypto.Decrypter) (security.PublicID, error) {
+func readIdentity(reader io.Reader, expectedChEnd string, dec crypto.Decrypter, v version.IPCVersion) (security.PublicID, error) {
 	// Read the message.
 	var msg identityMessage
 	if err := vom.NewDecoder(reader).Decode(&msg); err != nil {
@@ -149,19 +165,34 @@
 	}
 
 	// Decrypt the signature
-	r, err := dec.Decrypt(iobuf.NewSlice(msg.SignR))
-	if err != nil {
-		return nil, fmt.Errorf("failed to decrypt SignR: %v", err)
-	}
-	defer r.Release()
-	s, err := dec.Decrypt(iobuf.NewSlice(msg.SignS))
-	if err != nil {
-		return nil, fmt.Errorf("failed to decrypt SignS: %v", err)
-	}
-	defer s.Release()
-	// Validate the signature
-	if !ecdsa.Verify(id.PublicKey(), msg.ChannelID, bigInt(r), bigInt(s)) {
-		return nil, errInvalidSignatureInMessage
+	if v == version.IPCVersion1 {
+		r, err := dec.Decrypt(iobuf.NewSlice(msg.SignR))
+		if err != nil {
+			return nil, fmt.Errorf("failed to decrypt SignR: %v", err)
+		}
+		defer r.Release()
+		s, err := dec.Decrypt(iobuf.NewSlice(msg.SignS))
+		if err != nil {
+			return nil, fmt.Errorf("failed to decrypt SignS: %v", err)
+		}
+		defer s.Release()
+		if !ecdsa.Verify(id.PublicKey(), msg.ChannelID, bigInt(r), bigInt(s)) {
+			return nil, errInvalidSignatureInMessage
+		}
+	} else {
+		sigbytes, err := dec.Decrypt(iobuf.NewSlice(msg.Signature))
+		if err != nil {
+			return nil, fmt.Errorf("failed to decrypt Signature: %v", err)
+		}
+		defer sigbytes.Release()
+		var sig security.Signature
+		if err = vom.NewDecoder(bytes.NewBuffer(sigbytes.Contents)).Decode(&sig); err != nil {
+			return nil, fmt.Errorf("failed to decode security.Signature: %v", err)
+		}
+		// Validate the signature
+		if !sig.Verify(id.PublicKey(), msg.ChannelID) {
+			return nil, errInvalidSignatureInMessage
+		}
 	}
 
 	return id, nil
diff --git a/runtimes/google/ipc/stream/vc/vc.go b/runtimes/google/ipc/stream/vc/vc.go
index 7f70721..894928f 100644
--- a/runtimes/google/ipc/stream/vc/vc.go
+++ b/runtimes/google/ipc/stream/vc/vc.go
@@ -20,6 +20,7 @@
 
 	"veyron2"
 	"veyron2/ipc/stream"
+	"veyron2/ipc/version"
 	"veyron2/naming"
 	"veyron2/security"
 	"veyron2/vlog"
@@ -57,6 +58,7 @@
 	closeReason         string // reason why the VC was closed
 
 	helper Helper
+	version             version.IPCVersion
 }
 
 // Helper is the interface for functionality required by the stream.VC
@@ -88,6 +90,7 @@
 	Pool         *iobuf.Pool     // Byte pool used for read and write buffer allocations.
 	ReserveBytes uint            // Number of bytes to reserve in iobuf.Slices.
 	Helper       Helper
+	Version      version.IPCVersion
 }
 
 // LocalID is the interface for providing a PrivateID and a PublicIDStore to
@@ -161,6 +164,7 @@
 		nextConnectFID: id.Flow(NumReservedFlows + fidOffset),
 		crypter:        crypto.NewNullCrypter(),
 		helper:         p.Helper,
+		version:        p.Version,
 	}
 }
 
@@ -417,7 +421,7 @@
 	if err != nil {
 		return vc.err(fmt.Errorf("failed to create a Flow for authentication: %v", err))
 	}
-	rID, lID, err := authenticateAsClient(authConn, localID, crypter)
+	rID, lID, err := authenticateAsClient(authConn, localID, crypter, vc.version)
 	if err != nil {
 		return vc.err(fmt.Errorf("authentication failed: %v", err))
 	}
@@ -518,7 +522,7 @@
 		vc.mu.Lock()
 		vc.authFID = vc.findFlowLocked(authConn)
 		vc.mu.Unlock()
-		rID, lID, err := authenticateAsServer(authConn, localID, crypter)
+		rID, lID, err := authenticateAsServer(authConn, localID, crypter, vc.version)
 		if err != nil {
 			sendErr(fmt.Errorf("Authentication failed: %v", err))
 			return
diff --git a/runtimes/google/ipc/stream/vc/vc_test.go b/runtimes/google/ipc/stream/vc/vc_test.go
index f1b1e2e..9bcb602 100644
--- a/runtimes/google/ipc/stream/vc/vc_test.go
+++ b/runtimes/google/ipc/stream/vc/vc_test.go
@@ -23,6 +23,7 @@
 
 	"veyron2"
 	"veyron2/ipc/stream"
+	"veyron2/ipc/version"
 	"veyron2/naming"
 	"veyron2/security"
 )
@@ -100,7 +101,7 @@
 }
 
 func testHandshake(t *testing.T, security veyron2.VCSecurityLevel, localID, remoteID security.PublicID) {
-	h, vc := New(security)
+	h, vc := New(security, version.IPCVersion2)
 	flow, err := vc.Connect()
 	if err != nil {
 		t.Fatal(err)
@@ -126,7 +127,7 @@
 }
 
 func testConnect_Small(t *testing.T, security veyron2.VCSecurityLevel) {
-	h, vc := New(security)
+	h, vc := New(security, version.IPCVersion2)
 	defer h.Close()
 	flow, err := vc.Connect()
 	if err != nil {
@@ -138,7 +139,7 @@
 func TestConnect_SmallTLS(t *testing.T) { testConnect_Small(t, SecurityTLS) }
 
 func testConnect(t *testing.T, security veyron2.VCSecurityLevel) {
-	h, vc := New(security)
+	h, vc := New(security, version.IPCVersion2)
 	defer h.Close()
 	flow, err := vc.Connect()
 	if err != nil {
@@ -149,13 +150,26 @@
 func TestConnect(t *testing.T)    { testConnect(t, SecurityNone) }
 func TestConnectTLS(t *testing.T) { testConnect(t, SecurityTLS) }
 
+func testConnect_Version1(t *testing.T, security veyron2.VCSecurityLevel) {
+	h, vc := New(security, version.IPCVersion1)
+	defer h.Close()
+	flow, err := vc.Connect()
+	if err != nil {
+		t.Fatal(err)
+	}
+	testFlowEcho(t, flow, 10)
+}
+func TestConnect_Version1(t *testing.T)    { testConnect_Version1(t, SecurityNone) }
+func TestConnect_Version1TLS(t *testing.T) { testConnect_Version1(t, SecurityTLS) }
+
+
 // helper function for testing concurrent operations on multiple flows over the
 // same VC.  Such tests are most useful when running the race detector.
 // (go test -race ...)
 func testConcurrentFlows(t *testing.T, security veyron2.VCSecurityLevel, flows, gomaxprocs int) {
 	mp := runtime.GOMAXPROCS(gomaxprocs)
 	defer runtime.GOMAXPROCS(mp)
-	h, vc := New(security)
+	h, vc := New(security, version.IPCVersion2)
 	defer h.Close()
 
 	var wg sync.WaitGroup
@@ -182,7 +196,7 @@
 
 func testListen(t *testing.T, security veyron2.VCSecurityLevel) {
 	data := "the dark knight"
-	h, vc := New(security)
+	h, vc := New(security, version.IPCVersion2)
 	defer h.Close()
 	if err := h.VC.AcceptFlow(id.Flow(21)); err == nil {
 		t.Errorf("Expected AcceptFlow on a new flow to fail as Listen was not called")
@@ -229,7 +243,7 @@
 func TestListenTLS(t *testing.T) { testListen(t, SecurityTLS) }
 
 func testNewFlowAfterClose(t *testing.T, security veyron2.VCSecurityLevel) {
-	h, _ := New(security)
+	h, _ := New(security, version.IPCVersion2)
 	defer h.Close()
 	h.VC.Close("reason")
 	if err := h.VC.AcceptFlow(id.Flow(10)); err == nil {
@@ -240,7 +254,7 @@
 func TestNewFlowAfterCloseTLS(t *testing.T) { testNewFlowAfterClose(t, SecurityTLS) }
 
 func testConnectAfterClose(t *testing.T, security veyron2.VCSecurityLevel) {
-	h, vc := New(security)
+	h, vc := New(security, version.IPCVersion2)
 	defer h.Close()
 	h.VC.Close("myerr")
 	if f, err := vc.Connect(); f != nil || err == nil || !strings.Contains(err.Error(), "myerr") {
@@ -262,7 +276,7 @@
 // New creates both ends of a VC but returns only the "client" end (i.e., the
 // one that initiated the VC). The "server" end (the one that "accepted" the VC)
 // listens for flows and simply echoes data read.
-func New(security veyron2.VCSecurityLevel) (*helper, stream.VC) {
+func New(security veyron2.VCSecurityLevel, v version.IPCVersion) (*helper, stream.VC) {
 	clientH := &helper{bq: drrqueue.New(vc.MaxPayloadSizeBytes)}
 	serverH := &helper{bq: drrqueue.New(vc.MaxPayloadSizeBytes)}
 	clientH.otherEnd = serverH
@@ -280,6 +294,7 @@
 		RemoteEP: serverEP,
 		Pool:     iobuf.NewPool(0),
 		Helper:   clientH,
+		Version:  v,
 	}
 	serverParams := vc.Params{
 		VCI:      vci,
@@ -287,6 +302,7 @@
 		RemoteEP: clientEP,
 		Pool:     iobuf.NewPool(0),
 		Helper:   serverH,
+		Version:  v,
 	}
 
 	clientH.VC = vc.InternalNew(clientParams)
diff --git a/runtimes/google/ipc/stream/vif/vif.go b/runtimes/google/ipc/stream/vif/vif.go
index 15ea933..2bfa7bb 100644
--- a/runtimes/google/ipc/stream/vif/vif.go
+++ b/runtimes/google/ipc/stream/vif/vif.go
@@ -590,9 +590,9 @@
 }
 
 func (vif *VIF) newVC(vci id.VC, localEP, remoteEP naming.Endpoint, dialed bool) (*vc.VC, error) {
-	_, err := version.CommonVersion(localEP, remoteEP)
+	version, err := version.CommonVersion(localEP, remoteEP)
 	if vif.versions != nil {
-		_, err = vif.versions.CommonVersion(localEP, remoteEP)
+		version, err = vif.versions.CommonVersion(localEP, remoteEP)
 	}
 	if err != nil {
 		return nil, err
@@ -605,6 +605,7 @@
 		Pool:         vif.pool,
 		ReserveBytes: message.HeaderSizeBytes,
 		Helper:       vcHelper{vif},
+		Version:      version,
 	})
 	added, rq, wq := vif.vcMap.Insert(vc)
 	// Start vcWriteLoop
diff --git a/runtimes/google/ipc/version/version.go b/runtimes/google/ipc/version/version.go
index 5ad9aa8..a0fec38 100644
--- a/runtimes/google/ipc/version/version.go
+++ b/runtimes/google/ipc/version/version.go
@@ -21,7 +21,7 @@
 	// change that's not both forward and backward compatible.
 	// Min should be incremented whenever we want to remove
 	// support for old protocol versions.
-	supportedRange = &Range{Min: version.IPCVersion1, Max: version.IPCVersion1}
+	supportedRange = &Range{Min: version.IPCVersion1, Max: version.IPCVersion2}
 
 	// Export the methods on supportedRange.
 	Endpoint           = supportedRange.Endpoint
diff --git a/runtimes/google/security/identity_chain.go b/runtimes/google/security/identity_chain.go
index b6ad17b..2c3c4d8 100644
--- a/runtimes/google/security/identity_chain.go
+++ b/runtimes/google/security/identity_chain.go
@@ -122,8 +122,12 @@
 
 func (id *chainPrivateID) PublicID() security.PublicID { return id.publicID }
 
-func (id *chainPrivateID) Sign(message []byte) (signature security.Signature, err error) {
-	signature.R, signature.S, err = ecdsa.Sign(rand.Reader, id.privateKey, message)
+func (id *chainPrivateID) Sign(message []byte) (sig security.Signature, err error) {
+	r, s, err := ecdsa.Sign(rand.Reader, id.privateKey, message)
+	if err != nil {
+		return
+	}
+	sig.R, sig.S = r.Bytes(), s.Bytes()
 	return
 }
 
diff --git a/security/caveat/public_key_caveat.go b/security/caveat/public_key_caveat.go
index 0dcb615..975cbc4 100644
--- a/security/caveat/public_key_caveat.go
+++ b/security/caveat/public_key_caveat.go
@@ -2,12 +2,10 @@
 
 import (
 	"bytes"
-	"crypto/ecdsa"
 	"crypto/rand"
 	"crypto/sha256"
 	"encoding/binary"
 	"fmt"
-	"math/big"
 	"time"
 
 	"veyron2/security"
@@ -95,8 +93,7 @@
 	if err != nil {
 		return errPublicKeyCaveat(c, err)
 	}
-	var r, s big.Int
-	if !ecdsa.Verify(key, pkDischarge.contentHash(), r.SetBytes(pkDischarge.Signature.R), s.SetBytes(pkDischarge.Signature.S)) {
+	if !pkDischarge.Signature.Verify(key, pkDischarge.contentHash()) {
 		return errPublicKeyCaveat(c, fmt.Errorf("discharge %v has invalid signature", dis))
 	}
 	return nil
@@ -116,7 +113,7 @@
 
 	// Signature on the contents of the discharge obtained using the private key
 	// corresponding to the validaton key in the caveat.
-	Signature wire.Signature
+	Signature security.Signature
 }
 
 // CaveatID returns a unique identity for the discharge based on the random nonce and
@@ -130,13 +127,9 @@
 }
 
 // sign uses the provided identity to sign the contents of the discharge.
-func (d *publicKeyDischarge) sign(discharger security.PrivateID) error {
-	signature, err := discharger.Sign(d.contentHash())
-	if err != nil {
-		return err
-	}
-	d.Signature.Set(signature)
-	return nil
+func (d *publicKeyDischarge) sign(discharger security.PrivateID) (err error) {
+	d.Signature, err = discharger.Sign(d.contentHash())
+	return
 }
 
 func (d *publicKeyDischarge) contentHash() []byte {
diff --git a/services/wsprd/security/identity.go b/services/wsprd/security/identity.go
index f72ad24..2315b32 100644
--- a/services/wsprd/security/identity.go
+++ b/services/wsprd/security/identity.go
@@ -13,7 +13,6 @@
 package security
 
 import (
-	"crypto/ecdsa"
 	"crypto/sha256"
 	"io"
 	"sync"
@@ -116,7 +115,7 @@
 		return result, nil
 	}
 
-	if !ecdsa.Verify(rt.Identity().PublicID().PublicKey(), signed, sig.R, sig.S) {
+	if !sig.Verify(rt.Identity().PublicID().PublicKey(), signed) {
 		return nil, verror.NotAuthorizedf("signature verification failed")
 	}