diff --git a/cmd/signal.go b/cmd/signal.go index db1582c1c..c19a3011b 100644 --- a/cmd/signal.go +++ b/cmd/signal.go @@ -42,5 +42,5 @@ var ( ) func init() { - upCmd.PersistentFlags().IntVar(&port, "port", 10000, "Server port to listen on (e.g. 10000)") + signalCmd.PersistentFlags().IntVar(&port, "port", 10000, "Server port to listen on (e.g. 10000)") } diff --git a/cmd/up.go b/cmd/up.go index 776edc8e3..df8466ac8 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -6,9 +6,14 @@ import ( "github.com/spf13/cobra" "github.com/wiretrustee/wiretrustee/connection" sig "github.com/wiretrustee/wiretrustee/signal" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "os" ) +func toByte32(key wgtypes.Key) *[32]byte { + return (*[32]byte)(&key) +} + var ( upCmd = &cobra.Command{ Use: "up", @@ -18,8 +23,14 @@ var ( config, _ := Read(configPath) + myKey, err := wgtypes.ParseKey(config.PrivateKey) + if err != nil { + log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) + os.Exit(ExitSetupFailed) + } + ctx := context.Background() - signalClient, err := sig.NewClient(config.SignalAddr, ctx) + signalClient, err := sig.NewClient(config.SignalAddr, myKey, ctx) if err != nil { log.Errorf("error while connecting to the Signal Exchange Service %s: %s", config.SignalAddr, err) os.Exit(ExitSetupFailed) @@ -29,7 +40,7 @@ var ( engine := connection.NewEngine(signalClient, config.StunTurnURLs, config.WgIface, config.WgAddr) - err = engine.Start(config.PrivateKey, config.Peers) + err = engine.Start(myKey, config.Peers) //signalClient.WaitConnected() diff --git a/connection/engine.go b/connection/engine.go index 79ea07c1e..5399c9b21 100644 --- a/connection/engine.go +++ b/connection/engine.go @@ -40,17 +40,9 @@ func NewEngine(signal *signal.Client, stunsTurns []*ice.URL, wgIface string, wgA } } -func (e *Engine) Start(privateKey string, peers []Peer) error { +func (e *Engine) Start(myKey wgtypes.Key, peers []Peer) error { - // setup wireguard - myKey, err := wgtypes.ParseKey(privateKey) - myPubKey := myKey.PublicKey().String() - if err != nil { - log.Errorf("error parsing Wireguard key %s: [%s]", privateKey, err.Error()) - return err - } - - err = iface.Create(e.wgIface, e.wgIp) + err := iface.Create(e.wgIface, e.wgIp) if err != nil { log.Errorf("error while creating interface %s: [%s]", e.wgIface, err.Error()) return err @@ -68,7 +60,7 @@ func (e *Engine) Start(privateKey string, peers []Peer) error { return err } - e.receiveSignal(myPubKey) + e.receiveSignal() // initialize peer agents for _, peer := range peers { @@ -141,10 +133,12 @@ func (e *Engine) openPeerConnection(wgPort int, myKey wgtypes.Key, peer Peer) (* func signalCandidate(candidate ice.Candidate, myKey wgtypes.Key, remoteKey wgtypes.Key, s *signal.Client) error { err := s.Send(&sProto.Message{ - Type: sProto.Message_CANDIDATE, Key: myKey.PublicKey().String(), RemoteKey: remoteKey.String(), - Body: candidate.Marshal(), + Body: &sProto.Body{ + Type: sProto.Body_CANDIDATE, + Payload: candidate.Marshal(), + }, }) if err != nil { log.Errorf("failed signaling candidate to the remote peer %s %s", remoteKey.String(), err) @@ -157,18 +151,18 @@ func signalCandidate(candidate ice.Candidate, myKey wgtypes.Key, remoteKey wgtyp func signalAuth(uFrag string, pwd string, myKey wgtypes.Key, remoteKey wgtypes.Key, s *signal.Client, isAnswer bool) error { - var t sProto.Message_Type + var t sProto.Body_Type if isAnswer { - t = sProto.Message_ANSWER + t = sProto.Body_ANSWER } else { - t = sProto.Message_OFFER + t = sProto.Body_OFFER } - msg := signal.MarshalCredential(myKey.PublicKey().String(), remoteKey.String(), &signal.Credential{ + msg, err := signal.MarshalCredential(myKey, remoteKey, &signal.Credential{ UFrag: uFrag, Pwd: pwd}, t) - err := s.Send(msg) + err = s.Send(msg) if err != nil { return err } @@ -176,9 +170,9 @@ func signalAuth(uFrag string, pwd string, myKey wgtypes.Key, remoteKey wgtypes.K return nil } -func (e *Engine) receiveSignal(localKey string) { +func (e *Engine) receiveSignal() { // connect to a stream of messages coming from the signal server - e.signal.Receive(localKey, func(msg *sProto.Message) error { + e.signal.Receive(func(msg *sProto.Message) error { conn := e.conns[msg.Key] if conn == nil { @@ -189,8 +183,8 @@ func (e *Engine) receiveSignal(localKey string) { return fmt.Errorf("unknown peer %s", msg.Key) } - switch msg.Type { - case sProto.Message_OFFER: + switch msg.GetBody().Type { + case sProto.Body_OFFER: remoteCred, err := signal.UnMarshalCredential(msg) if err != nil { return err @@ -205,7 +199,7 @@ func (e *Engine) receiveSignal(localKey string) { } return nil - case sProto.Message_ANSWER: + case sProto.Body_ANSWER: remoteCred, err := signal.UnMarshalCredential(msg) if err != nil { return err @@ -219,9 +213,9 @@ func (e *Engine) receiveSignal(localKey string) { return err } - case sProto.Message_CANDIDATE: + case sProto.Body_CANDIDATE: - candidate, err := ice.UnmarshalCandidate(msg.Body) + candidate, err := ice.UnmarshalCandidate(msg.GetBody().Payload) if err != nil { log.Errorf("failed on parsing remote candidate %s -> %s", candidate, err) return err diff --git a/signal/client.go b/signal/client.go index debf635fa..353806858 100644 --- a/signal/client.go +++ b/signal/client.go @@ -4,8 +4,10 @@ import ( "context" "fmt" "github.com/cenkalti/backoff/v4" + pb "github.com/golang/protobuf/proto" log "github.com/sirupsen/logrus" "github.com/wiretrustee/wiretrustee/signal/proto" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/keepalive" @@ -21,20 +23,22 @@ import ( // Wraps the Signal Exchange Service gRpc client type Client struct { - realClient proto.SignalExchangeClient - signalConn *grpc.ClientConn - ctx context.Context - stream proto.SignalExchange_ConnectStreamClient + key wgtypes.Key + encryptionKey string + realClient proto.SignalExchangeClient + signalConn *grpc.ClientConn + ctx context.Context + stream proto.SignalExchange_ConnectStreamClient //waiting group to notify once stream is connected connWg sync.WaitGroup //todo use a channel instead?? } // Closes underlying connections to the Signal Exchange -func (client *Client) Close() error { - return client.signalConn.Close() +func (c *Client) Close() error { + return c.signalConn.Close() } -func NewClient(addr string, ctx context.Context) (*Client, error) { +func NewClient(addr string, key wgtypes.Key, ctx context.Context) (*Client, error) { conn, err := grpc.DialContext( ctx, @@ -55,6 +59,7 @@ func NewClient(addr string, ctx context.Context) (*Client, error) { realClient: proto.NewSignalExchangeClient(conn), ctx: ctx, signalConn: conn, + key: key, }, nil } @@ -62,8 +67,8 @@ func NewClient(addr string, ctx context.Context) (*Client, error) { // The messages will be handled by msgHandler function provided. // This function runs a goroutine underneath and reconnects to the Signal Exchange if errors occur (e.g. Exchange restart) // The key is the identifier of our Peer (could be Wireguard public key) -func (client *Client) Receive(key string, msgHandler func(msg *proto.Message) error) { - client.connWg.Add(1) +func (c *Client) Receive(msgHandler func(msg *proto.Message) error) { + c.connWg.Add(1) go func() { var backOff = &backoff.ExponentialBackOff{ @@ -77,10 +82,10 @@ func (client *Client) Receive(key string, msgHandler func(msg *proto.Message) er } operation := func() error { - err := client.connect(key, msgHandler) + err := c.connect(c.key.PublicKey().String(), msgHandler) if err != nil { log.Warnf("disconnected from the Signal Exchange due to an error %s. Retrying ... ", err) - client.connWg.Add(1) + c.connWg.Add(1) return err } @@ -96,44 +101,44 @@ func (client *Client) Receive(key string, msgHandler func(msg *proto.Message) er }() } -func (client *Client) connect(key string, msgHandler func(msg *proto.Message) error) error { - client.stream = nil +func (c *Client) connect(key string, msgHandler func(msg *proto.Message) error) error { + c.stream = nil // add key fingerprint to the request header to be identified on the server side md := metadata.New(map[string]string{proto.HeaderId: key}) - ctx := metadata.NewOutgoingContext(client.ctx, md) + ctx := metadata.NewOutgoingContext(c.ctx, md) ctx, cancel := context.WithCancel(ctx) defer cancel() - stream, err := client.realClient.ConnectStream(ctx) + stream, err := c.realClient.ConnectStream(ctx) - client.stream = stream + c.stream = stream if err != nil { return err } //connection established we are good to use the stream - client.connWg.Done() + c.connWg.Done() log.Infof("connected to the Signal Exchange Stream") - return client.receive(stream, msgHandler) + return c.receive(stream, msgHandler) } // Waits until the client is connected to the message stream -func (client *Client) WaitConnected() { - client.connWg.Wait() +func (c *Client) WaitConnected() { + c.connWg.Wait() } // Sends a message to the remote Peer through the Signal Exchange using established stream connection to the Signal Server // The Client.Receive method must be called before sending messages to establish initial connection to the Signal Exchange // Client.connWg can be used to wait -func (client *Client) SendToStream(msg *proto.Message) error { +func (c *Client) SendToStream(msg *proto.EncryptedMessage) error { - if client.stream == nil { + if c.stream == nil { return fmt.Errorf("connection to the Signal Exchnage has not been established yet. Please call Client.Receive before sending messages") } - err := client.stream.Send(msg) + err := c.stream.Send(msg) if err != nil { log.Errorf("error while sending message to peer [%s] [error: %v]", msg.RemoteKey, err) return err @@ -142,10 +147,57 @@ func (client *Client) SendToStream(msg *proto.Message) error { return nil } -// Sends a message to the remote Peer through the Signal Exchange. -func (client *Client) Send(msg *proto.Message) error { +// decryptMessage decrypts the body of the msg using Wireguard private key and Remote peer's public key +func (c *Client) decryptMessage(msg *proto.EncryptedMessage) (*proto.Message, error) { + remoteKey, err := wgtypes.ParseKey(msg.GetKey()) + if err != nil { + return nil, err + } + decryptedBody, err := Decrypt(msg.GetBody(), remoteKey, c.key) + body := &proto.Body{} + err = pb.Unmarshal(decryptedBody, body) + if err != nil { + return nil, err + } - _, err := client.realClient.Connect(context.TODO(), msg) + return &proto.Message{ + Key: msg.Key, + RemoteKey: msg.RemoteKey, + Body: body, + }, nil +} + +// encryptMessage encrypts the body of the msg using Wireguard private key and Remote peer's public key +func (c *Client) encryptMessage(msg *proto.Message) (*proto.EncryptedMessage, error) { + body, err := pb.Marshal(msg.GetBody()) + if err != nil { + return nil, err + } + remoteKey, err := wgtypes.ParseKey(msg.RemoteKey) + if err != nil { + return nil, err + } + + encryptedBody, err := Encrypt(body, remoteKey, c.key) + if err != nil { + return nil, err + } + + return &proto.EncryptedMessage{ + Key: msg.GetKey(), + RemoteKey: msg.GetRemoteKey(), + Body: encryptedBody, + }, nil +} + +// Sends a message to the remote Peer through the Signal Exchange. +func (c *Client) Send(msg *proto.Message) error { + + encryptedMessage, err := c.encryptMessage(msg) + if err != nil { + return err + } + _, err = c.realClient.Send(context.TODO(), encryptedMessage) if err != nil { log.Errorf("error while sending message to peer [%s] [error: %v]", msg.RemoteKey, err) return err @@ -155,7 +207,7 @@ func (client *Client) Send(msg *proto.Message) error { } // Receives messages from other peers coming through the Signal Exchange -func (client *Client) receive(stream proto.SignalExchange_ConnectStreamClient, +func (c *Client) receive(stream proto.SignalExchange_ConnectStreamClient, msgHandler func(msg *proto.Message) error) error { for { @@ -172,10 +224,14 @@ func (client *Client) receive(stream proto.SignalExchange_ConnectStreamClient, } else if err != nil { return err } - log.Debugf("received a new message from Peer [fingerprint: %s] [type %s]", msg.Key, msg.Type) + log.Debugf("received a new message from Peer [fingerprint: %s]", msg.Key) - //todo decrypt - err = msgHandler(msg) + decryptedMessage, err := c.decryptMessage(msg) + if err != nil { + log.Errorf("failed decrypting message of Peer [key: %s] error: [%s]", msg.Key, err.Error()) + } + + err = msgHandler(decryptedMessage) if err != nil { log.Errorf("error while handling message of Peer [key: %s] error: [%s]", msg.Key, err.Error()) @@ -185,7 +241,8 @@ func (client *Client) receive(stream proto.SignalExchange_ConnectStreamClient, } func UnMarshalCredential(msg *proto.Message) (*Credential, error) { - credential := strings.Split(msg.Body, ":") + + credential := strings.Split(msg.GetBody().GetPayload(), ":") if len(credential) != 2 { return nil, fmt.Errorf("error parsing message body %s", msg.Body) } @@ -195,13 +252,15 @@ func UnMarshalCredential(msg *proto.Message) (*Credential, error) { }, nil } -func MarshalCredential(ourKey string, remoteKey string, credential *Credential, t proto.Message_Type) *proto.Message { +func MarshalCredential(myKey wgtypes.Key, remoteKey wgtypes.Key, credential *Credential, t proto.Body_Type) (*proto.Message, error) { return &proto.Message{ - Type: t, - Key: ourKey, - RemoteKey: remoteKey, - Body: fmt.Sprintf("%s:%s", credential.UFrag, credential.Pwd), - } + Key: myKey.PublicKey().String(), + RemoteKey: remoteKey.String(), + Body: &proto.Body{ + Type: t, + Payload: fmt.Sprintf("%s:%s", credential.UFrag, credential.Pwd), + }, + }, nil } type Credential struct { diff --git a/signal/encryption.go b/signal/encryption.go index 8b6136216..2e10d66de 100644 --- a/signal/encryption.go +++ b/signal/encryption.go @@ -8,30 +8,30 @@ import ( ) // As set of tools to encrypt/decrypt messages being sent through the Signal Exchange Service. -// We want to make sure that the Connection Candidates and other irrelevant (to the Signal Exchange) information can't be read anywhere else but the Peer the message is being sent to. +// We want to make sure that the Connection Candidates and other irrelevant (to the Signal Exchange) +// information can't be read anywhere else but the Peer the message is being sent to. // These tools use Golang crypto package (Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate) // Wireguard keys are used for encryption // Encrypts a message using local Wireguard private key and remote peer's public key. -func EncryptMessage(msg []byte, privateKey wgtypes.Key, remotePubKey wgtypes.Key) ([]byte, error) { +func Encrypt(msg []byte, peersPublicKey wgtypes.Key, privateKey wgtypes.Key) ([]byte, error) { nonce, err := genNonce() if err != nil { return nil, err } - - return box.Seal(nil, msg, nonce, toByte32(remotePubKey), toByte32(privateKey)), nil + return box.Seal(nonce[:], msg, nonce, toByte32(peersPublicKey), toByte32(privateKey)), nil } // Decrypts a message that has been encrypted by the remote peer using Wireguard private key and remote peer's public key. -func DecryptMessage(encryptedMsg []byte, privateKey wgtypes.Key, remotePubKey wgtypes.Key) ([]byte, error) { +func Decrypt(encryptedMsg []byte, peersPublicKey wgtypes.Key, privateKey wgtypes.Key) ([]byte, error) { nonce, err := genNonce() if err != nil { return nil, err } - - opened, ok := box.Open(nil, encryptedMsg, nonce, toByte32(remotePubKey), toByte32(privateKey)) + copy(nonce[:], encryptedMsg[:24]) + opened, ok := box.Open(nil, encryptedMsg[24:], nonce, toByte32(peersPublicKey), toByte32(privateKey)) if !ok { - return nil, fmt.Errorf("failed to decrypt message from peer %s", remotePubKey.String()) + return nil, fmt.Errorf("failed to decrypt message from peer %s", peersPublicKey.String()) } return opened, nil diff --git a/signal/proto/signalexchange.pb.go b/signal/proto/signalexchange.pb.go index 1860380ca..2478a8d73 100644 --- a/signal/proto/signalexchange.pb.go +++ b/signal/proto/signalexchange.pb.go @@ -26,41 +26,101 @@ var _ = math.Inf const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // Message type -type Message_Type int32 +type Body_Type int32 const ( - Message_OFFER Message_Type = 0 - Message_ANSWER Message_Type = 1 - Message_CANDIDATE Message_Type = 2 + Body_OFFER Body_Type = 0 + Body_ANSWER Body_Type = 1 + Body_CANDIDATE Body_Type = 2 ) -var Message_Type_name = map[int32]string{ +var Body_Type_name = map[int32]string{ 0: "OFFER", 1: "ANSWER", 2: "CANDIDATE", } -var Message_Type_value = map[string]int32{ +var Body_Type_value = map[string]int32{ "OFFER": 0, "ANSWER": 1, "CANDIDATE": 2, } -func (x Message_Type) String() string { - return proto.EnumName(Message_Type_name, int32(x)) +func (x Body_Type) String() string { + return proto.EnumName(Body_Type_name, int32(x)) } -func (Message_Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_bf680d70b8e3473f, []int{0, 0} +func (Body_Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_bf680d70b8e3473f, []int{2, 0} } +// Used for sending through signal. +// The body of this message is the Body message encrypted with the Wireguard private key and the remote Peer key +type EncryptedMessage struct { + // a sha256 fingerprint of the Wireguard public key + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + // a sha256 fingerprint of the Wireguard public key of the remote peer to connect to + RemoteKey string `protobuf:"bytes,3,opt,name=remoteKey,proto3" json:"remoteKey,omitempty"` + // encrypted message body + Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EncryptedMessage) Reset() { *m = EncryptedMessage{} } +func (m *EncryptedMessage) String() string { return proto.CompactTextString(m) } +func (*EncryptedMessage) ProtoMessage() {} +func (*EncryptedMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_bf680d70b8e3473f, []int{0} +} + +func (m *EncryptedMessage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EncryptedMessage.Unmarshal(m, b) +} +func (m *EncryptedMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EncryptedMessage.Marshal(b, m, deterministic) +} +func (m *EncryptedMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_EncryptedMessage.Merge(m, src) +} +func (m *EncryptedMessage) XXX_Size() int { + return xxx_messageInfo_EncryptedMessage.Size(m) +} +func (m *EncryptedMessage) XXX_DiscardUnknown() { + xxx_messageInfo_EncryptedMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_EncryptedMessage proto.InternalMessageInfo + +func (m *EncryptedMessage) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *EncryptedMessage) GetRemoteKey() string { + if m != nil { + return m.RemoteKey + } + return "" +} + +func (m *EncryptedMessage) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +// A decrypted representation of the EncryptedMessage. Used locally before/after encryption type Message struct { - Type Message_Type `protobuf:"varint,1,opt,name=type,proto3,enum=signalexchange.Message_Type" json:"type,omitempty"` // a sha256 fingerprint of the Wireguard public key Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` // a sha256 fingerprint of the Wireguard public key of the remote peer to connect to RemoteKey string `protobuf:"bytes,3,opt,name=remoteKey,proto3" json:"remoteKey,omitempty"` - Body string `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` + Body *Body `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -70,7 +130,7 @@ func (m *Message) Reset() { *m = Message{} } func (m *Message) String() string { return proto.CompactTextString(m) } func (*Message) ProtoMessage() {} func (*Message) Descriptor() ([]byte, []int) { - return fileDescriptor_bf680d70b8e3473f, []int{0} + return fileDescriptor_bf680d70b8e3473f, []int{1} } func (m *Message) XXX_Unmarshal(b []byte) error { @@ -91,13 +151,6 @@ func (m *Message) XXX_DiscardUnknown() { var xxx_messageInfo_Message proto.InternalMessageInfo -func (m *Message) GetType() Message_Type { - if m != nil { - return m.Type - } - return Message_OFFER -} - func (m *Message) GetKey() string { if m != nil { return m.Key @@ -112,39 +165,93 @@ func (m *Message) GetRemoteKey() string { return "" } -func (m *Message) GetBody() string { +func (m *Message) GetBody() *Body { if m != nil { return m.Body } + return nil +} + +// Actual body of the message that can contain credentials (type OFFER/ANSWER) or connection Candidate +// This part will be encrypted +type Body struct { + Type Body_Type `protobuf:"varint,1,opt,name=type,proto3,enum=signalexchange.Body_Type" json:"type,omitempty"` + Payload string `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Body) Reset() { *m = Body{} } +func (m *Body) String() string { return proto.CompactTextString(m) } +func (*Body) ProtoMessage() {} +func (*Body) Descriptor() ([]byte, []int) { + return fileDescriptor_bf680d70b8e3473f, []int{2} +} + +func (m *Body) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Body.Unmarshal(m, b) +} +func (m *Body) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Body.Marshal(b, m, deterministic) +} +func (m *Body) XXX_Merge(src proto.Message) { + xxx_messageInfo_Body.Merge(m, src) +} +func (m *Body) XXX_Size() int { + return xxx_messageInfo_Body.Size(m) +} +func (m *Body) XXX_DiscardUnknown() { + xxx_messageInfo_Body.DiscardUnknown(m) +} + +var xxx_messageInfo_Body proto.InternalMessageInfo + +func (m *Body) GetType() Body_Type { + if m != nil { + return m.Type + } + return Body_OFFER +} + +func (m *Body) GetPayload() string { + if m != nil { + return m.Payload + } return "" } func init() { - proto.RegisterEnum("signalexchange.Message_Type", Message_Type_name, Message_Type_value) + proto.RegisterEnum("signalexchange.Body_Type", Body_Type_name, Body_Type_value) + proto.RegisterType((*EncryptedMessage)(nil), "signalexchange.EncryptedMessage") proto.RegisterType((*Message)(nil), "signalexchange.Message") + proto.RegisterType((*Body)(nil), "signalexchange.Body") } func init() { proto.RegisterFile("signalexchange.proto", fileDescriptor_bf680d70b8e3473f) } var fileDescriptor_bf680d70b8e3473f = []byte{ - // 272 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x50, 0xcd, 0x4a, 0xf3, 0x40, - 0x14, 0xed, 0xb4, 0xf9, 0x1a, 0x72, 0xa1, 0x21, 0x5c, 0x3e, 0x30, 0x94, 0x2e, 0x42, 0x56, 0x59, - 0x48, 0x5a, 0xea, 0x52, 0x5c, 0xc4, 0x36, 0x15, 0x11, 0x2b, 0x24, 0x05, 0xc1, 0x5d, 0x9a, 0x5e, - 0xc7, 0x62, 0x9b, 0x09, 0x93, 0x11, 0x9c, 0x37, 0xf1, 0x25, 0x7c, 0x47, 0xe9, 0x34, 0x20, 0x0a, - 0xdd, 0xb8, 0x9a, 0xc3, 0xf9, 0x9b, 0xc3, 0x85, 0xff, 0xcd, 0x96, 0x57, 0xc5, 0x8e, 0xde, 0xcb, - 0x97, 0xa2, 0xe2, 0x14, 0xd7, 0x52, 0x28, 0x81, 0xee, 0x4f, 0x76, 0x18, 0x70, 0x21, 0xf8, 0x8e, - 0xc6, 0x46, 0x5d, 0xbf, 0x3d, 0x8f, 0x37, 0xd4, 0x94, 0x72, 0x5b, 0x2b, 0x21, 0x8f, 0x89, 0xf0, - 0x93, 0x81, 0x7d, 0x4f, 0x4d, 0x53, 0x70, 0xc2, 0x09, 0x58, 0x4a, 0xd7, 0xe4, 0xb3, 0x80, 0x45, - 0xee, 0x74, 0x14, 0xff, 0xfa, 0xa2, 0xb5, 0xc5, 0x2b, 0x5d, 0x53, 0x66, 0x9c, 0xe8, 0x41, 0xef, - 0x95, 0xb4, 0xdf, 0x0d, 0x58, 0xe4, 0x64, 0x07, 0x88, 0x23, 0x70, 0x24, 0xed, 0x85, 0xa2, 0x3b, - 0xd2, 0x7e, 0xcf, 0xf0, 0xdf, 0x04, 0x22, 0x58, 0x6b, 0xb1, 0xd1, 0xbe, 0x65, 0x04, 0x83, 0xc3, - 0x73, 0xb0, 0x0e, 0x8d, 0xe8, 0xc0, 0xbf, 0x87, 0xc5, 0x22, 0xcd, 0xbc, 0x0e, 0x02, 0xf4, 0x93, - 0x65, 0xfe, 0x98, 0x66, 0x1e, 0xc3, 0x01, 0x38, 0xb3, 0x64, 0x39, 0xbf, 0x9d, 0x27, 0xab, 0xd4, - 0xeb, 0x4e, 0x3f, 0x18, 0xb8, 0xb9, 0xd9, 0x95, 0xb6, 0xbb, 0xf0, 0x0a, 0xec, 0x99, 0xa8, 0x2a, - 0x2a, 0x15, 0x9e, 0x9d, 0xd8, 0x3c, 0x3c, 0x25, 0x84, 0x1d, 0xbc, 0x81, 0x41, 0x1b, 0xcf, 0x95, - 0xa4, 0x62, 0xff, 0x97, 0x92, 0x88, 0x4d, 0xd8, 0xb5, 0xf3, 0x64, 0xc7, 0x97, 0xc7, 0x4b, 0xf7, - 0xcd, 0x73, 0xf1, 0x15, 0x00, 0x00, 0xff, 0xff, 0x20, 0x13, 0xc1, 0xe1, 0xa6, 0x01, 0x00, 0x00, + // 319 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x4f, 0x4b, 0xfb, 0x40, + 0x10, 0xed, 0xb6, 0xf9, 0xb5, 0x64, 0x7e, 0xb6, 0x84, 0xa1, 0x87, 0x58, 0x3c, 0x84, 0x9c, 0x72, + 0xd0, 0x54, 0xea, 0xd1, 0x53, 0xff, 0xa4, 0x20, 0x6a, 0x85, 0xa4, 0x28, 0x7a, 0x4b, 0x93, 0x31, + 0x16, 0xdb, 0x6c, 0xd8, 0xac, 0xe0, 0x1e, 0xfc, 0x60, 0x7e, 0x3b, 0xe9, 0xb6, 0xa2, 0x06, 0x41, + 0x10, 0x4f, 0x3b, 0xf3, 0xf6, 0xcd, 0x7b, 0x6f, 0x97, 0x81, 0x6e, 0xb9, 0xcc, 0xf2, 0x78, 0x45, + 0xcf, 0xc9, 0x43, 0x9c, 0x67, 0xe4, 0x17, 0x82, 0x4b, 0x8e, 0x9d, 0xaf, 0x68, 0xcf, 0xc9, 0x38, + 0xcf, 0x56, 0xd4, 0xd7, 0xb7, 0x8b, 0xa7, 0xfb, 0x7e, 0x4a, 0x65, 0x22, 0x96, 0x85, 0xe4, 0x62, + 0x3b, 0xe1, 0x5e, 0x83, 0x15, 0xe4, 0x89, 0x50, 0x85, 0xa4, 0xf4, 0x92, 0xca, 0x32, 0xce, 0x08, + 0x2d, 0x68, 0x3c, 0x92, 0xb2, 0xeb, 0x0e, 0xf3, 0xcc, 0x70, 0x53, 0xe2, 0x01, 0x98, 0x82, 0xd6, + 0x5c, 0xd2, 0x39, 0x29, 0xbb, 0xa1, 0xf1, 0x0f, 0x00, 0x11, 0x8c, 0x05, 0x4f, 0x95, 0x6d, 0x38, + 0xcc, 0xdb, 0x0b, 0x75, 0xed, 0x26, 0xd0, 0xfa, 0xad, 0x9c, 0xf7, 0x49, 0xee, 0xff, 0xa0, 0xeb, + 0x57, 0x5e, 0x3a, 0xe2, 0xa9, 0xda, 0x99, 0xbc, 0x80, 0xb1, 0xe9, 0xf0, 0x08, 0x0c, 0xa9, 0x0a, + 0xb2, 0x99, 0xc3, 0xbc, 0xce, 0x60, 0xff, 0xbb, 0x09, 0x7f, 0xae, 0x0a, 0x0a, 0x35, 0x0d, 0x6d, + 0x68, 0x15, 0xb1, 0x5a, 0xf1, 0x38, 0xdd, 0x85, 0x7a, 0x6f, 0xdd, 0x43, 0x30, 0x36, 0x3c, 0x34, + 0xe1, 0xdf, 0xd5, 0x74, 0x1a, 0x84, 0x56, 0x0d, 0x01, 0x9a, 0xc3, 0x59, 0x74, 0x13, 0x84, 0x16, + 0xc3, 0x36, 0x98, 0xe3, 0xe1, 0x6c, 0x72, 0x36, 0x19, 0xce, 0x03, 0xab, 0x3e, 0x78, 0x65, 0xd0, + 0x89, 0xb4, 0x55, 0xb0, 0xb3, 0xc2, 0x0b, 0x30, 0x22, 0xca, 0x53, 0x74, 0xaa, 0x19, 0xaa, 0x9f, + 0xdc, 0xfb, 0x91, 0xe1, 0xd6, 0xf0, 0x16, 0xda, 0x63, 0x9e, 0xe7, 0x94, 0xc8, 0x48, 0x0a, 0x8a, + 0xd7, 0x7f, 0x23, 0xeb, 0xb1, 0x63, 0x36, 0x32, 0xef, 0x5a, 0xfe, 0xe9, 0x76, 0x2d, 0x9a, 0xfa, + 0x38, 0x79, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xb8, 0xb5, 0xbf, 0xeb, 0x53, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -160,7 +267,7 @@ const _ = grpc.SupportPackageIsVersion4 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type SignalExchangeClient interface { // Synchronously connect to the Signal Exchange service offering connection candidates and waiting for connection candidates from the other party (remote peer) - Connect(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) + Send(ctx context.Context, in *EncryptedMessage, opts ...grpc.CallOption) (*EncryptedMessage, error) // Connect to the Signal Exchange service offering connection candidates and maintain a channel for receiving candidates from the other party (remote peer) ConnectStream(ctx context.Context, opts ...grpc.CallOption) (SignalExchange_ConnectStreamClient, error) } @@ -173,9 +280,9 @@ func NewSignalExchangeClient(cc *grpc.ClientConn) SignalExchangeClient { return &signalExchangeClient{cc} } -func (c *signalExchangeClient) Connect(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) { - out := new(Message) - err := c.cc.Invoke(ctx, "/signalexchange.SignalExchange/Connect", in, out, opts...) +func (c *signalExchangeClient) Send(ctx context.Context, in *EncryptedMessage, opts ...grpc.CallOption) (*EncryptedMessage, error) { + out := new(EncryptedMessage) + err := c.cc.Invoke(ctx, "/signalexchange.SignalExchange/Send", in, out, opts...) if err != nil { return nil, err } @@ -192,8 +299,8 @@ func (c *signalExchangeClient) ConnectStream(ctx context.Context, opts ...grpc.C } type SignalExchange_ConnectStreamClient interface { - Send(*Message) error - Recv() (*Message, error) + Send(*EncryptedMessage) error + Recv() (*EncryptedMessage, error) grpc.ClientStream } @@ -201,12 +308,12 @@ type signalExchangeConnectStreamClient struct { grpc.ClientStream } -func (x *signalExchangeConnectStreamClient) Send(m *Message) error { +func (x *signalExchangeConnectStreamClient) Send(m *EncryptedMessage) error { return x.ClientStream.SendMsg(m) } -func (x *signalExchangeConnectStreamClient) Recv() (*Message, error) { - m := new(Message) +func (x *signalExchangeConnectStreamClient) Recv() (*EncryptedMessage, error) { + m := new(EncryptedMessage) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } @@ -216,7 +323,7 @@ func (x *signalExchangeConnectStreamClient) Recv() (*Message, error) { // SignalExchangeServer is the server API for SignalExchange service. type SignalExchangeServer interface { // Synchronously connect to the Signal Exchange service offering connection candidates and waiting for connection candidates from the other party (remote peer) - Connect(context.Context, *Message) (*Message, error) + Send(context.Context, *EncryptedMessage) (*EncryptedMessage, error) // Connect to the Signal Exchange service offering connection candidates and maintain a channel for receiving candidates from the other party (remote peer) ConnectStream(SignalExchange_ConnectStreamServer) error } @@ -225,8 +332,8 @@ type SignalExchangeServer interface { type UnimplementedSignalExchangeServer struct { } -func (*UnimplementedSignalExchangeServer) Connect(ctx context.Context, req *Message) (*Message, error) { - return nil, status.Errorf(codes.Unimplemented, "method Connect not implemented") +func (*UnimplementedSignalExchangeServer) Send(ctx context.Context, req *EncryptedMessage) (*EncryptedMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Send not implemented") } func (*UnimplementedSignalExchangeServer) ConnectStream(srv SignalExchange_ConnectStreamServer) error { return status.Errorf(codes.Unimplemented, "method ConnectStream not implemented") @@ -236,20 +343,20 @@ func RegisterSignalExchangeServer(s *grpc.Server, srv SignalExchangeServer) { s.RegisterService(&_SignalExchange_serviceDesc, srv) } -func _SignalExchange_Connect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Message) +func _SignalExchange_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EncryptedMessage) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(SignalExchangeServer).Connect(ctx, in) + return srv.(SignalExchangeServer).Send(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/signalexchange.SignalExchange/Connect", + FullMethod: "/signalexchange.SignalExchange/Send", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SignalExchangeServer).Connect(ctx, req.(*Message)) + return srv.(SignalExchangeServer).Send(ctx, req.(*EncryptedMessage)) } return interceptor(ctx, in, info, handler) } @@ -259,8 +366,8 @@ func _SignalExchange_ConnectStream_Handler(srv interface{}, stream grpc.ServerSt } type SignalExchange_ConnectStreamServer interface { - Send(*Message) error - Recv() (*Message, error) + Send(*EncryptedMessage) error + Recv() (*EncryptedMessage, error) grpc.ServerStream } @@ -268,12 +375,12 @@ type signalExchangeConnectStreamServer struct { grpc.ServerStream } -func (x *signalExchangeConnectStreamServer) Send(m *Message) error { +func (x *signalExchangeConnectStreamServer) Send(m *EncryptedMessage) error { return x.ServerStream.SendMsg(m) } -func (x *signalExchangeConnectStreamServer) Recv() (*Message, error) { - m := new(Message) +func (x *signalExchangeConnectStreamServer) Recv() (*EncryptedMessage, error) { + m := new(EncryptedMessage) if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err } @@ -285,8 +392,8 @@ var _SignalExchange_serviceDesc = grpc.ServiceDesc{ HandlerType: (*SignalExchangeServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "Connect", - Handler: _SignalExchange_Connect_Handler, + MethodName: "Send", + Handler: _SignalExchange_Send_Handler, }, }, Streams: []grpc.StreamDesc{ diff --git a/signal/proto/signalexchange.proto b/signal/proto/signalexchange.proto index af46dfe9d..4c3ab7c27 100644 --- a/signal/proto/signalexchange.proto +++ b/signal/proto/signalexchange.proto @@ -8,27 +8,45 @@ package signalexchange; service SignalExchange { // Synchronously connect to the Signal Exchange service offering connection candidates and waiting for connection candidates from the other party (remote peer) - rpc Connect(Message) returns (Message) {} + rpc Send(EncryptedMessage) returns (EncryptedMessage) {} // Connect to the Signal Exchange service offering connection candidates and maintain a channel for receiving candidates from the other party (remote peer) - rpc ConnectStream(stream Message) returns (stream Message) {} + rpc ConnectStream(stream EncryptedMessage) returns (stream EncryptedMessage) {} } -message Message { +// Used for sending through signal. +// The body of this message is the Body message encrypted with the Wireguard private key and the remote Peer key +message EncryptedMessage { + // Wireguard public key + string key = 2; + + // Wireguard public key of the remote peer to connect to + string remoteKey = 3; + + // encrypted message Body + bytes body = 4; +} + +// A decrypted representation of the EncryptedMessage. Used locally before/after encryption +message Message { + // Wireguard public key + string key = 2; + + // Wireguard public key of the remote peer to connect to + string remoteKey = 3; + + Body body = 4; +} + +// Actual body of the message that can contain credentials (type OFFER/ANSWER) or connection Candidate +// This part will be encrypted +message Body { // Message type enum Type { OFFER = 0; ANSWER = 1; CANDIDATE = 2; } - Type type = 1; - - // a sha256 fingerprint of the Wireguard public key - string key = 2; - - // a sha256 fingerprint of the Wireguard public key of the remote peer to connect to - string remoteKey = 3; - - string body = 4; + string payload = 2; } \ No newline at end of file diff --git a/signal/signal.go b/signal/signal.go index a212d460f..91b5bd5f3 100644 --- a/signal/signal.go +++ b/signal/signal.go @@ -27,7 +27,7 @@ func NewServer() *SignalExchangeServer { } } -func (s *SignalExchangeServer) Connect(ctx context.Context, msg *proto.Message) (*proto.Message, error) { +func (s *SignalExchangeServer) Send(ctx context.Context, msg *proto.EncryptedMessage) (*proto.EncryptedMessage, error) { if _, found := s.registry.Peers[msg.Key]; !found { return nil, fmt.Errorf("unknown peer %s", msg.Key) @@ -44,7 +44,7 @@ func (s *SignalExchangeServer) Connect(ctx context.Context, msg *proto.Message) log.Warnf("message from peer [%s] can't be forwarded to peer [%s] because destination peer is not connected", msg.Key, msg.RemoteKey) //todo respond to the sender? } - return &proto.Message{}, nil + return &proto.EncryptedMessage{}, nil } func (s *SignalExchangeServer) ConnectStream(stream proto.SignalExchange_ConnectStreamServer) error {