Adding Inbound Version Negotiation

+ Error handling for missing private key setting
This commit is contained in:
Sarah Jamie Lewis 2017-06-27 10:39:33 -07:00
parent a2fa40492a
commit f4ed1c244b
7 changed files with 73 additions and 1 deletions

View File

@ -75,6 +75,11 @@ func (ah *HiddenServiceAuthChannel) Closed(err error) {
// returned, it will be sent as the ChannelResult message. // returned, it will be sent as the ChannelResult message.
// Remote -> [Open Authentication Channel] -> Local // Remote -> [Open Authentication Channel] -> Local
func (ah *HiddenServiceAuthChannel) OpenInbound(channel *Channel, oc *Protocol_Data_Control.OpenChannel) ([]byte, error) { func (ah *HiddenServiceAuthChannel) OpenInbound(channel *Channel, oc *Protocol_Data_Control.OpenChannel) ([]byte, error) {
if ah.PrivateKey == nil {
return nil, utils.PrivateKeyNotSetError
}
ah.channel = channel ah.channel = channel
clientCookie, _ := proto.GetExtension(oc, Protocol_Data_AuthHiddenService.E_ClientCookie) clientCookie, _ := proto.GetExtension(oc, Protocol_Data_AuthHiddenService.E_ClientCookie)
if len(clientCookie.([]byte)[:]) != 16 { if len(clientCookie.([]byte)[:]) != 16 {
@ -92,6 +97,12 @@ func (ah *HiddenServiceAuthChannel) OpenInbound(channel *Channel, oc *Protocol_D
// returned, it will be sent as the OpenChannel message. // returned, it will be sent as the OpenChannel message.
// Local -> [Open Authentication Channel] -> Remote // Local -> [Open Authentication Channel] -> Remote
func (ah *HiddenServiceAuthChannel) OpenOutbound(channel *Channel) ([]byte, error) { func (ah *HiddenServiceAuthChannel) OpenOutbound(channel *Channel) ([]byte, error) {
if ah.PrivateKey == nil {
return nil, utils.PrivateKeyNotSetError
}
ah.channel = channel ah.channel = channel
messageBuilder := new(utils.MessageBuilder) messageBuilder := new(utils.MessageBuilder)
return messageBuilder.OpenAuthenticationChannel(ah.channel.ID, ah.GenClientCookie()), nil return messageBuilder.OpenAuthenticationChannel(ah.channel.ID, ah.GenClientCookie()), nil

View File

@ -71,9 +71,10 @@ func GetOpenAuthenticationChannelMessage() *Protocol_Data_Control.OpenChannel {
} }
func TestAuthenticationOpenInbound(t *testing.T) { func TestAuthenticationOpenInbound(t *testing.T) {
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key")
opm := GetOpenAuthenticationChannelMessage() opm := GetOpenAuthenticationChannelMessage()
authHandler := new(HiddenServiceAuthChannel) authHandler := new(HiddenServiceAuthChannel)
authHandler.PrivateKey = privateKey
channel := Channel{ID: 1} channel := Channel{ID: 1}
response, err := authHandler.OpenInbound(&channel, opm) response, err := authHandler.OpenInbound(&channel, opm)
@ -90,7 +91,9 @@ func TestAuthenticationOpenInbound(t *testing.T) {
} }
func TestAuthenticationOpenOutbound(t *testing.T) { func TestAuthenticationOpenOutbound(t *testing.T) {
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key")
authHandler := new(HiddenServiceAuthChannel) authHandler := new(HiddenServiceAuthChannel)
authHandler.PrivateKey = privateKey
channel := Channel{ID: 1} channel := Channel{ID: 1}
response, err := authHandler.OpenOutbound(&channel) response, err := authHandler.OpenOutbound(&channel)

View File

@ -24,7 +24,9 @@ type AutoConnectionHandler struct {
} }
// Init ... // Init ...
// TODO: Split this into client and server init
func (ach *AutoConnectionHandler) Init(privateKey *rsa.PrivateKey, serverHostname string) { func (ach *AutoConnectionHandler) Init(privateKey *rsa.PrivateKey, serverHostname string) {
ach.handlerMap = make(map[string]func() channels.Handler) ach.handlerMap = make(map[string]func() channels.Handler)
ach.RegisterChannelHandler("im.ricochet.auth.hidden-service", func() channels.Handler { ach.RegisterChannelHandler("im.ricochet.auth.hidden-service", func() channels.Handler {
hsau := new(channels.HiddenServiceAuthChannel) hsau := new(channels.HiddenServiceAuthChannel)

View File

@ -35,6 +35,10 @@ func HandleInboundConnection(c *Connection) *InboundConnectionHandler {
// assume they are required to send a contact request before any other activity. // assume they are required to send a contact request before any other activity.
func (ich *InboundConnectionHandler) ProcessAuthAsServer(privateKey *rsa.PrivateKey, sach func(hostname string, publicKey rsa.PublicKey) (allowed, known bool)) error { func (ich *InboundConnectionHandler) ProcessAuthAsServer(privateKey *rsa.PrivateKey, sach func(hostname string, publicKey rsa.PublicKey) (allowed, known bool)) error {
if privateKey == nil {
return utils.PrivateKeyNotSetError
}
ach := new(AutoConnectionHandler) ach := new(AutoConnectionHandler)
ach.Init(privateKey, ich.connection.RemoteHostname) ach.Init(privateKey, ich.connection.RemoteHostname)
ach.SetServerAuthHandler(sach) ach.SetServerAuthHandler(sach)

View File

@ -4,6 +4,7 @@ import (
"crypto/rsa" "crypto/rsa"
"errors" "errors"
"github.com/s-rah/go-ricochet/channels" "github.com/s-rah/go-ricochet/channels"
"github.com/s-rah/go-ricochet/utils"
"github.com/s-rah/go-ricochet/policies" "github.com/s-rah/go-ricochet/policies"
"log" "log"
) )
@ -33,6 +34,11 @@ func HandleOutboundConnection(c *Connection) *OutboundConnectionHandler {
// accepts us as a known contact. Unknown contacts will generally need to send a contact // accepts us as a known contact. Unknown contacts will generally need to send a contact
// request before any other activity. // request before any other activity.
func (och *OutboundConnectionHandler) ProcessAuthAsClient(privateKey *rsa.PrivateKey) (bool, error) { func (och *OutboundConnectionHandler) ProcessAuthAsClient(privateKey *rsa.PrivateKey) (bool, error) {
if privateKey == nil {
return false, utils.PrivateKeyNotSetError
}
ach := new(AutoConnectionHandler) ach := new(AutoConnectionHandler)
ach.Init(privateKey, och.connection.RemoteHostname) ach.Init(privateKey, och.connection.RemoteHostname)

View File

@ -53,3 +53,46 @@ func negotiateVersion(conn net.Conn, remoteHostname string) (*connection.Connect
} }
// NegotiateVersionInbound takes in a connection and performs version negotiation
// as if that connection was a client. Returns a ricochet connection if successful
// error otherwise.
func NegotiateVersionInbound(conn net.Conn) (*connection.Connection, error) {
versions := []byte{0x49, 0x4D, 0x01, 0x01}
// Read version response header
header := make([]byte, 3)
if _, err := io.ReadAtLeast(conn, header, len(header)); err != nil {
return nil, err
}
if header[0] != versions[0] || header[1] != versions[1] || header[2] < 1 {
return nil, utils.VersionNegotiationError
}
// Read list of supported versions (which is header[2] bytes long)
versionList := make([]byte, header[2])
if _, err := io.ReadAtLeast(conn, versionList, len(versionList)); err != nil {
return nil, utils.VersionNegotiationError
}
selectedVersion := byte(0xff)
for _, v := range versionList {
if v == 0x01 {
selectedVersion = v
break
}
}
if n, err := conn.Write([]byte{selectedVersion}); err != nil || n < 1 {
return nil, utils.VersionNegotiationFailed
}
if selectedVersion == 0xff {
return nil, utils.VersionNegotiationFailed
}
rc := connection.NewInboundConnection(conn)
return rc, nil
}

View File

@ -24,6 +24,9 @@ const (
ActionTimedOutError = Error("ActionTimedOutError") ActionTimedOutError = Error("ActionTimedOutError")
ClientFailedToAuthenticateError = Error("ClientFailedToAuthenticateError") ClientFailedToAuthenticateError = Error("ClientFailedToAuthenticateError")
PrivateKeyNotSetError = Error("PrivateKeyNotSetError")
) )
// RecoverFromError doesn't really recover from anything....see comment below // RecoverFromError doesn't really recover from anything....see comment below