handshake proto version

This commit is contained in:
Sergey Cherepanov 2023-05-22 13:51:13 +02:00
parent 94cfb82691
commit 4a7bf3ef46
No known key found for this signature in database
GPG Key ID: 87F8EDE8FBDF637C
8 changed files with 172 additions and 47 deletions

View File

@ -9,12 +9,16 @@ import (
"go.uber.org/zap"
)
func newNoVerifyChecker() handshake.CredentialChecker {
return &noVerifyChecker{cred: &handshakeproto.Credentials{Type: handshakeproto.CredentialsType_SkipVerify}}
func newNoVerifyChecker(protoVersion uint32) handshake.CredentialChecker {
return &noVerifyChecker{
protoVersion: protoVersion,
cred: &handshakeproto.Credentials{Type: handshakeproto.CredentialsType_SkipVerify},
}
}
type noVerifyChecker struct {
cred *handshakeproto.Credentials
protoVersion uint32
cred *handshakeproto.Credentials
}
func (n noVerifyChecker) MakeCredentials(sc sec.SecureConn) *handshakeproto.Credentials {
@ -22,15 +26,22 @@ func (n noVerifyChecker) MakeCredentials(sc sec.SecureConn) *handshakeproto.Cred
}
func (n noVerifyChecker) CheckCredential(sc sec.SecureConn, cred *handshakeproto.Credentials) (identity []byte, err error) {
if cred.Version != n.protoVersion {
return nil, handshake.ErrIncompatibleVersion
}
return nil, nil
}
func newPeerSignVerifier(account *accountdata.AccountKeys) handshake.CredentialChecker {
return &peerSignVerifier{account: account}
func newPeerSignVerifier(protoVersion uint32, account *accountdata.AccountKeys) handshake.CredentialChecker {
return &peerSignVerifier{
protoVersion: protoVersion,
account: account,
}
}
type peerSignVerifier struct {
account *accountdata.AccountKeys
protoVersion uint32
account *accountdata.AccountKeys
}
func (p *peerSignVerifier) MakeCredentials(sc sec.SecureConn) *handshakeproto.Credentials {
@ -52,6 +63,9 @@ func (p *peerSignVerifier) MakeCredentials(sc sec.SecureConn) *handshakeproto.Cr
}
func (p *peerSignVerifier) CheckCredential(sc sec.SecureConn, cred *handshakeproto.Credentials) (identity []byte, err error) {
if cred.Version != p.protoVersion {
return nil, handshake.ErrIncompatibleVersion
}
if cred.Type != handshakeproto.CredentialsType_SignedPeerIds {
return nil, handshake.ErrSkipVerifyNotAllowed
}

View File

@ -20,8 +20,8 @@ func TestPeerSignVerifier_CheckCredential(t *testing.T) {
identity1, _ := a1.SignKey.GetPublic().Marshall()
identity2, _ := a2.SignKey.GetPublic().Marshall()
cc1 := newPeerSignVerifier(a1)
cc2 := newPeerSignVerifier(a2)
cc1 := newPeerSignVerifier(0, a1)
cc2 := newPeerSignVerifier(0, a2)
c1 := newTestSC(a2.PeerId)
c2 := newTestSC(a1.PeerId)
@ -40,6 +40,31 @@ func TestPeerSignVerifier_CheckCredential(t *testing.T) {
assert.EqualError(t, err, handshake.ErrInvalidCredentials.Error())
}
func TestIncompatibleVersion(t *testing.T) {
a1 := newTestAccData(t)
a2 := newTestAccData(t)
_, _ = a1.SignKey.GetPublic().Marshall()
identity2, _ := a2.SignKey.GetPublic().Marshall()
cc1 := newPeerSignVerifier(0, a1)
cc2 := newPeerSignVerifier(1, a2)
c1 := newTestSC(a2.PeerId)
c2 := newTestSC(a1.PeerId)
cr1 := cc1.MakeCredentials(c1)
cr2 := cc2.MakeCredentials(c2)
id1, err := cc1.CheckCredential(c1, cr2)
assert.NoError(t, err)
assert.Equal(t, identity2, id1)
_, err = cc2.CheckCredential(c2, cr1)
assert.EqualError(t, err, handshake.ErrIncompatibleVersion.Error())
_, err = cc1.CheckCredential(c1, cr1)
assert.EqualError(t, err, handshake.ErrInvalidCredentials.Error())
}
func newTestAccData(t *testing.T) *accountdata.AccountKeys {
as := accounttest.AccountTestService{}
require.NoError(t, as.Init(nil))

View File

@ -34,6 +34,8 @@ var (
ErrSkipVerifyNotAllowed = handshakeError{handshakeproto.Error_SkipVerifyNotAllowed}
ErrUnexpected = handshakeError{handshakeproto.Error_Unexpected}
ErrIncompatibleVersion = handshakeError{handshakeproto.Error_IncompatibleVersion}
ErrGotNotAHandshakeMessage = errors.New("go not a handshake message")
)

View File

@ -11,16 +11,10 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"net"
"net/http"
_ "net/http/pprof"
"testing"
"time"
)
func init() {
go http.ListenAndServe(":6060", nil)
}
var noVerifyChecker = &testCredChecker{
makeCred: &handshakeproto.Credentials{Type: handshakeproto.CredentialsType_SkipVerify},
checkCred: func(sc sec.SecureConn, cred *handshakeproto.Credentials) (identity []byte, err error) {
@ -324,6 +318,26 @@ func TestIncomingHandshake(t *testing.T) {
res := <-handshakeResCh
require.EqualError(t, res.err, ErrInvalidCredentials.Error())
})
t.Run("invalid cred version", func(t *testing.T) {
c1, c2 := newConnPair(t)
var handshakeResCh = make(chan handshakeRes, 1)
go func() {
identity, err := IncomingHandshake(nil, c1, &testCredChecker{makeCred: noVerifyChecker.makeCred, checkErr: ErrIncompatibleVersion})
handshakeResCh <- handshakeRes{identity: identity, err: err}
}()
h := newHandshake()
h.conn = c2
// write credentials
require.NoError(t, h.writeCredentials(noVerifyChecker.MakeCredentials(c2)))
// except ack with error
msg, err := h.readMsg()
require.NoError(t, err)
require.Nil(t, msg.cred)
require.Equal(t, handshakeproto.Error_IncompatibleVersion, msg.ack.Error)
res := <-handshakeResCh
require.EqualError(t, res.err, ErrIncompatibleVersion.Error())
})
t.Run("write cred instead ack", func(t *testing.T) {
c1, c2 := newConnPair(t)
var handshakeResCh = make(chan handshakeRes, 1)

View File

@ -58,6 +58,7 @@ const (
Error_UnexpectedPayload Error = 3
Error_SkipVerifyNotAllowed Error = 4
Error_DeadlineExceeded Error = 5
Error_IncompatibleVersion Error = 6
)
var Error_name = map[int32]string{
@ -67,6 +68,7 @@ var Error_name = map[int32]string{
3: "UnexpectedPayload",
4: "SkipVerifyNotAllowed",
5: "DeadlineExceeded",
6: "IncompatibleVersion",
}
var Error_value = map[string]int32{
@ -76,6 +78,7 @@ var Error_value = map[string]int32{
"UnexpectedPayload": 3,
"SkipVerifyNotAllowed": 4,
"DeadlineExceeded": 5,
"IncompatibleVersion": 6,
}
func (x Error) String() string {
@ -89,6 +92,7 @@ func (Error) EnumDescriptor() ([]byte, []int) {
type Credentials struct {
Type CredentialsType `protobuf:"varint,1,opt,name=type,proto3,enum=anyHandshake.CredentialsType" json:"type,omitempty"`
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
Version uint32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
}
func (m *Credentials) Reset() { *m = Credentials{} }
@ -138,6 +142,13 @@ func (m *Credentials) GetPayload() []byte {
return nil
}
func (m *Credentials) GetVersion() uint32 {
if m != nil {
return m.Version
}
return 0
}
type PayloadSignedPeerIds struct {
// account identity
Identity []byte `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"`
@ -249,30 +260,32 @@ func init() {
}
var fileDescriptor_60283fc75f020893 = []byte{
// 362 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0xcd, 0x8e, 0xda, 0x30,
0x18, 0x8c, 0x21, 0xb4, 0xe8, 0x2b, 0xa5, 0xc6, 0xa5, 0x55, 0x54, 0xa9, 0x11, 0xe2, 0x44, 0x39,
0x40, 0xff, 0x5e, 0x80, 0x16, 0xaa, 0x72, 0x41, 0x28, 0xb4, 0x3d, 0x70, 0x73, 0xe3, 0xaf, 0x60,
0x61, 0x39, 0x91, 0x13, 0x28, 0xb9, 0xed, 0x23, 0xec, 0x63, 0xed, 0x91, 0xe3, 0x1e, 0x57, 0xf0,
0x22, 0x2b, 0x0c, 0x2c, 0x61, 0x4f, 0x7b, 0xb1, 0xe7, 0x1b, 0x8f, 0x67, 0xc6, 0x32, 0xf4, 0x34,
0xa6, 0xdd, 0x04, 0xc3, 0xa5, 0xc1, 0x04, 0xcd, 0x4a, 0x86, 0xd8, 0x9d, 0x73, 0x2d, 0x92, 0x39,
0x5f, 0xe4, 0x50, 0x6c, 0xa2, 0x34, 0xea, 0xda, 0x35, 0x39, 0xb3, 0x1d, 0x4b, 0xb0, 0x0a, 0xd7,
0xd9, 0xcf, 0x13, 0xd7, 0x9c, 0xc2, 0x8b, 0xef, 0x06, 0x05, 0xea, 0x54, 0x72, 0x95, 0xb0, 0x4f,
0xe0, 0xa6, 0x59, 0x8c, 0x1e, 0x69, 0x90, 0x56, 0xf5, 0xf3, 0xfb, 0x4e, 0x5e, 0xdb, 0xc9, 0x09,
0x7f, 0x65, 0x31, 0x06, 0x56, 0xca, 0x3c, 0x78, 0x1e, 0xf3, 0x4c, 0x45, 0x5c, 0x78, 0x85, 0x06,
0x69, 0x55, 0x82, 0xd3, 0xd8, 0xfc, 0x01, 0xf5, 0xf1, 0x01, 0x4e, 0xe4, 0x4c, 0xa3, 0x18, 0x23,
0x9a, 0xa1, 0x48, 0xd8, 0x3b, 0x28, 0x4b, 0x6b, 0x94, 0x66, 0x36, 0xa8, 0x12, 0x3c, 0xcc, 0x8c,
0x81, 0x9b, 0xc8, 0x99, 0x3e, 0x5a, 0x59, 0xdc, 0xfc, 0x08, 0xc5, 0x5e, 0xb8, 0x60, 0x1f, 0xa0,
0x84, 0xc6, 0x44, 0xe6, 0x58, 0xee, 0xf5, 0x65, 0xb9, 0xc1, 0xfe, 0x28, 0x38, 0x28, 0xda, 0x5f,
0xe1, 0xd5, 0xa3, 0xb2, 0xac, 0x0a, 0x30, 0x59, 0xc8, 0xf8, 0x0f, 0x1a, 0xf9, 0x2f, 0xa3, 0x0e,
0xab, 0xc1, 0xcb, 0x8b, 0x56, 0x94, 0xb4, 0xaf, 0x08, 0x94, 0xac, 0x0d, 0x2b, 0x83, 0x3b, 0x5a,
0x2a, 0x45, 0x9d, 0xfd, 0xb5, 0xdf, 0x1a, 0xd7, 0x31, 0x86, 0x29, 0x0a, 0x4a, 0xd8, 0x5b, 0x60,
0x43, 0xbd, 0xe2, 0x4a, 0x8a, 0x5c, 0x00, 0x2d, 0xb0, 0x37, 0x50, 0x3b, 0xeb, 0x8e, 0xaf, 0xa6,
0x45, 0xe6, 0x41, 0xfd, 0x9c, 0x3a, 0x8a, 0xd2, 0x9e, 0x52, 0xd1, 0x7f, 0x14, 0xd4, 0x65, 0x75,
0xa0, 0x7d, 0xe4, 0x42, 0x49, 0x8d, 0x83, 0x75, 0x88, 0x28, 0x50, 0xd0, 0xd2, 0xb7, 0xfe, 0xcd,
0xd6, 0x27, 0x9b, 0xad, 0x4f, 0xee, 0xb6, 0x3e, 0xb9, 0xde, 0xf9, 0xce, 0x66, 0xe7, 0x3b, 0xb7,
0x3b, 0xdf, 0x99, 0xb6, 0x9f, 0xfe, 0xf3, 0x7f, 0x9f, 0xd9, 0xed, 0xcb, 0x7d, 0x00, 0x00, 0x00,
0xff, 0xff, 0xa0, 0x48, 0xdf, 0x7a, 0x2e, 0x02, 0x00, 0x00,
// 395 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcd, 0x6e, 0x13, 0x31,
0x10, 0xc7, 0xd7, 0x4d, 0x52, 0xaa, 0x21, 0x2d, 0xee, 0x34, 0xc0, 0x0a, 0x89, 0x55, 0x94, 0x53,
0xc8, 0x21, 0xe1, 0xeb, 0x05, 0x02, 0x2d, 0x22, 0x97, 0xaa, 0xda, 0x42, 0x0f, 0xdc, 0xdc, 0xf5,
0xd0, 0x5a, 0x31, 0xf6, 0xca, 0x76, 0x43, 0xf7, 0x2d, 0xb8, 0xf2, 0x46, 0x1c, 0x7b, 0xe4, 0x88,
0x92, 0x17, 0x41, 0x71, 0x12, 0x92, 0x70, 0xea, 0xc5, 0x9e, 0x8f, 0x9f, 0xfd, 0xff, 0x8f, 0x65,
0x18, 0x1a, 0x0a, 0x03, 0x4f, 0xc5, 0x8d, 0x23, 0x4f, 0x6e, 0xa2, 0x0a, 0x1a, 0x5c, 0x0b, 0x23,
0xfd, 0xb5, 0x18, 0x6f, 0x44, 0xa5, 0xb3, 0xc1, 0x0e, 0xe2, 0xea, 0xd7, 0xd5, 0x7e, 0x2c, 0x60,
0x53, 0x98, 0xea, 0xe3, 0xaa, 0xd6, 0x09, 0xf0, 0xf0, 0xbd, 0x23, 0x49, 0x26, 0x28, 0xa1, 0x3d,
0xbe, 0x82, 0x7a, 0xa8, 0x4a, 0x4a, 0x59, 0x9b, 0x75, 0x0f, 0x5e, 0x3f, 0xef, 0x6f, 0xb2, 0xfd,
0x0d, 0xf0, 0x53, 0x55, 0x52, 0x1e, 0x51, 0x4c, 0xe1, 0x41, 0x29, 0x2a, 0x6d, 0x85, 0x4c, 0x77,
0xda, 0xac, 0xdb, 0xcc, 0x57, 0xe9, 0xbc, 0x33, 0x21, 0xe7, 0x95, 0x35, 0x69, 0xad, 0xcd, 0xba,
0xfb, 0xf9, 0x2a, 0xed, 0x7c, 0x80, 0xd6, 0xd9, 0x02, 0x3a, 0x57, 0x57, 0x86, 0xe4, 0x19, 0x91,
0x1b, 0x49, 0x8f, 0xcf, 0x60, 0x4f, 0x45, 0x89, 0x50, 0x45, 0x0b, 0xcd, 0xfc, 0x5f, 0x8e, 0x08,
0x75, 0xaf, 0xae, 0xcc, 0x52, 0x24, 0xc6, 0x9d, 0x97, 0x50, 0x1b, 0x16, 0x63, 0x7c, 0x01, 0x0d,
0x72, 0xce, 0xba, 0xa5, 0xed, 0xa3, 0x6d, 0xdb, 0x27, 0xf3, 0x56, 0xbe, 0x20, 0x7a, 0x6f, 0xe1,
0xd1, 0x7f, 0x63, 0xe0, 0x01, 0xc0, 0xf9, 0x58, 0x95, 0x17, 0xe4, 0xd4, 0xd7, 0x8a, 0x27, 0x78,
0x08, 0xfb, 0x5b, 0xae, 0x38, 0xeb, 0xfd, 0x64, 0xd0, 0x88, 0xd7, 0xe0, 0x1e, 0xd4, 0x4f, 0x6f,
0xb4, 0xe6, 0xc9, 0xfc, 0xd8, 0x67, 0x43, 0xb7, 0x25, 0x15, 0x81, 0x24, 0x67, 0xf8, 0x04, 0x70,
0x64, 0x26, 0x42, 0x2b, 0xb9, 0x21, 0xc0, 0x77, 0xf0, 0x31, 0x1c, 0xae, 0xb9, 0xe5, 0xd4, 0xbc,
0x86, 0x29, 0xb4, 0xd6, 0xaa, 0xa7, 0x36, 0x0c, 0xb5, 0xb6, 0xdf, 0x49, 0xf2, 0x3a, 0xb6, 0x80,
0x1f, 0x93, 0x90, 0x5a, 0x19, 0x3a, 0xb9, 0x2d, 0x88, 0x24, 0x49, 0xde, 0xc0, 0xa7, 0x70, 0x34,
0x32, 0x85, 0xfd, 0x56, 0x8a, 0xa0, 0x2e, 0x35, 0x5d, 0x2c, 0x5e, 0x92, 0xef, 0xbe, 0x3b, 0xfe,
0x35, 0xcd, 0xd8, 0xdd, 0x34, 0x63, 0x7f, 0xa6, 0x19, 0xfb, 0x31, 0xcb, 0x92, 0xbb, 0x59, 0x96,
0xfc, 0x9e, 0x65, 0xc9, 0x97, 0xde, 0xfd, 0x3f, 0xcb, 0xe5, 0x6e, 0xdc, 0xde, 0xfc, 0x0d, 0x00,
0x00, 0xff, 0xff, 0xbf, 0x78, 0x2f, 0x36, 0x61, 0x02, 0x00, 0x00,
}
func (m *Credentials) Marshal() (dAtA []byte, err error) {
@ -295,6 +308,11 @@ func (m *Credentials) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.Version != 0 {
i = encodeVarintHandshake(dAtA, i, uint64(m.Version))
i--
dAtA[i] = 0x18
}
if len(m.Payload) > 0 {
i -= len(m.Payload)
copy(dAtA[i:], m.Payload)
@ -399,6 +417,9 @@ func (m *Credentials) Size() (n int) {
if l > 0 {
n += 1 + l + sovHandshake(uint64(l))
}
if m.Version != 0 {
n += 1 + sovHandshake(uint64(m.Version))
}
return n
}
@ -519,6 +540,25 @@ func (m *Credentials) Unmarshal(dAtA []byte) error {
m.Payload = []byte{}
}
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType)
}
m.Version = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHandshake
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Version |= uint32(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipHandshake(dAtA[iNdEx:])

View File

@ -36,6 +36,7 @@ Successful handshake scheme:
message Credentials {
CredentialsType type = 1;
bytes payload = 2;
uint32 version = 3;
}
enum CredentialsType {
@ -66,4 +67,5 @@ enum Error {
UnexpectedPayload = 3;
SkipVerifyNotAllowed = 4;
DeadlineExceeded = 5;
IncompatibleVersion = 6;
}

View File

@ -44,10 +44,11 @@ type SecureService interface {
}
type secureService struct {
p2pTr *libp2ptls.Transport
account *accountdata.AccountKeys
key crypto.PrivKey
nodeconf nodeconf.Service
p2pTr *libp2ptls.Transport
account *accountdata.AccountKeys
key crypto.PrivKey
nodeconf nodeconf.Service
protoVersion uint32
noVerifyChecker handshake.CredentialChecker
peerSignVerifier handshake.CredentialChecker
@ -64,8 +65,8 @@ func (s *secureService) Init(a *app.App) (err error) {
return
}
s.noVerifyChecker = newNoVerifyChecker()
s.peerSignVerifier = newPeerSignVerifier(account.Account())
s.noVerifyChecker = newNoVerifyChecker(s.protoVersion)
s.peerSignVerifier = newPeerSignVerifier(s.protoVersion, account.Account())
s.nodeconf = a.MustComponent(nodeconf.CName).(nodeconf.Service)

View File

@ -5,6 +5,7 @@ import (
"github.com/anytypeio/any-sync/accountservice"
"github.com/anytypeio/any-sync/app"
"github.com/anytypeio/any-sync/net/peer"
"github.com/anytypeio/any-sync/net/secureservice/handshake"
"github.com/anytypeio/any-sync/nodeconf"
"github.com/anytypeio/any-sync/nodeconf/mock_nodeconf"
"github.com/anytypeio/any-sync/testutil/testnodeconf"
@ -19,7 +20,7 @@ var ctx = context.Background()
func TestHandshake(t *testing.T) {
nc := testnodeconf.GenNodeConfig(2)
fxS := newFixture(t, nc, nc.GetAccountService(0))
fxS := newFixture(t, nc, nc.GetAccountService(0), 0)
defer fxS.Finish(t)
sc, cc := net.Pipe()
@ -35,7 +36,7 @@ func TestHandshake(t *testing.T) {
resCh <- ar
}()
fxC := newFixture(t, nc, nc.GetAccountService(1))
fxC := newFixture(t, nc, nc.GetAccountService(1), 0)
defer fxC.Finish(t)
secConn, err := fxC.SecureOutbound(ctx, cc)
@ -52,13 +53,39 @@ func TestHandshake(t *testing.T) {
assert.Equal(t, marshalledId, accId)
}
func newFixture(t *testing.T, nc *testnodeconf.Config, acc accountservice.Service) *fixture {
func TestHandshakeIncompatibleVersion(t *testing.T) {
nc := testnodeconf.GenNodeConfig(2)
fxS := newFixture(t, nc, nc.GetAccountService(0), 0)
defer fxS.Finish(t)
sc, cc := net.Pipe()
type acceptRes struct {
ctx context.Context
conn net.Conn
err error
}
resCh := make(chan acceptRes)
go func() {
var ar acceptRes
ar.ctx, ar.conn, ar.err = fxS.SecureInbound(ctx, sc)
resCh <- ar
}()
fxC := newFixture(t, nc, nc.GetAccountService(1), 1)
defer fxC.Finish(t)
_, err := fxC.SecureOutbound(ctx, cc)
require.EqualError(t, err, handshake.ErrIncompatibleVersion.Error())
res := <-resCh
require.EqualError(t, res.err, handshake.ErrIncompatibleVersion.Error())
}
func newFixture(t *testing.T, nc *testnodeconf.Config, acc accountservice.Service, protoVersion uint32) *fixture {
fx := &fixture{
ctrl: gomock.NewController(t),
secureService: New().(*secureService),
acc: acc,
a: new(app.App),
}
fx.secureService.protoVersion = protoVersion
fx.mockNodeConf = mock_nodeconf.NewMockService(fx.ctrl)
fx.mockNodeConf.EXPECT().Init(gomock.Any())
fx.mockNodeConf.EXPECT().Name().Return(nodeconf.CName).AnyTimes()