forked from openprivacy/libricochet-go
Merge branch 'v1-cleanup' of openprivacy/libricochet-go into master
This commit is contained in:
commit
46e3eeeb7d
|
@ -1,250 +0,0 @@
|
|||
package channels
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"encoding/asn1"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/wire/auth"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/wire/control"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
// InvalidClientCookieError - returned when the client provides a cookie with the wrong length
|
||||
InvalidClientCookieError = utils.Error("InvalidClientCookieError")
|
||||
)
|
||||
|
||||
// HiddenServiceAuthChannel wraps implementation of im.ricochet.auth.hidden-service"
|
||||
type HiddenServiceAuthChannel struct {
|
||||
// PrivateKey must be set for client-side authentication channels
|
||||
Identity identity.Identity
|
||||
ServerHostname string
|
||||
|
||||
// Callbacks
|
||||
ClientAuthResult func(accepted, isKnownContact bool)
|
||||
ServerAuthValid func(hostname string, publicKey rsa.PublicKey) (allowed, known bool)
|
||||
ServerAuthInvalid func(err error)
|
||||
|
||||
// Internal state
|
||||
clientCookie, serverCookie [16]byte
|
||||
channel *Channel
|
||||
}
|
||||
|
||||
// Type returns the type string for this channel, e.g. "im.ricochet.chat".
|
||||
func (ah *HiddenServiceAuthChannel) Type() string {
|
||||
return "im.ricochet.auth.hidden-service"
|
||||
}
|
||||
|
||||
// Singleton Returns whether or not the given channel type is a singleton
|
||||
func (ah *HiddenServiceAuthChannel) Singleton() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// OnlyClientCanOpen ...
|
||||
func (ah *HiddenServiceAuthChannel) OnlyClientCanOpen() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Bidirectional Returns whether or not the given channel allows anyone to send messages
|
||||
func (ah *HiddenServiceAuthChannel) Bidirectional() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// RequiresAuthentication Returns whether or not the given channel type requires authentication
|
||||
func (ah *HiddenServiceAuthChannel) RequiresAuthentication() string {
|
||||
return "none"
|
||||
}
|
||||
|
||||
// Closed is called when the channel is closed for any reason.
|
||||
func (ah *HiddenServiceAuthChannel) Closed(err error) {
|
||||
|
||||
}
|
||||
|
||||
// OpenInbound is the first method called for an inbound channel request.
|
||||
// If an error is returned, the channel is rejected. If a RawMessage is
|
||||
// returned, it will be sent as the ChannelResult message.
|
||||
// Remote -> [Open Authentication Channel] -> Local
|
||||
func (ah *HiddenServiceAuthChannel) OpenInbound(channel *Channel, oc *Protocol_Data_Control.OpenChannel) ([]byte, error) {
|
||||
|
||||
if !ah.Identity.Initialized() {
|
||||
return nil, utils.PrivateKeyNotSetError
|
||||
}
|
||||
|
||||
ah.channel = channel
|
||||
clientCookie, _ := proto.GetExtension(oc, Protocol_Data_AuthHiddenService.E_ClientCookie)
|
||||
if len(clientCookie.([]byte)[:]) != 16 {
|
||||
// reutrn without opening channel.
|
||||
return nil, InvalidClientCookieError
|
||||
}
|
||||
ah.AddClientCookie(clientCookie.([]byte)[:])
|
||||
messageBuilder := new(utils.MessageBuilder)
|
||||
channel.Pending = false
|
||||
return messageBuilder.ConfirmAuthChannel(ah.channel.ID, ah.GenServerCookie()), nil
|
||||
}
|
||||
|
||||
// OpenOutbound is the first method called for an outbound channel request.
|
||||
// If an error is returned, the channel is not opened. If a RawMessage is
|
||||
// returned, it will be sent as the OpenChannel message.
|
||||
// Local -> [Open Authentication Channel] -> Remote
|
||||
func (ah *HiddenServiceAuthChannel) OpenOutbound(channel *Channel) ([]byte, error) {
|
||||
|
||||
if !ah.Identity.Initialized() {
|
||||
return nil, utils.PrivateKeyNotSetError
|
||||
}
|
||||
|
||||
ah.channel = channel
|
||||
messageBuilder := new(utils.MessageBuilder)
|
||||
return messageBuilder.OpenAuthenticationChannel(ah.channel.ID, ah.GenClientCookie()), nil
|
||||
}
|
||||
|
||||
// OpenOutboundResult is called when a response is received for an
|
||||
// outbound OpenChannel request. If `err` is non-nil, the channel was
|
||||
// rejected and Closed will be called immediately afterwards. `raw`
|
||||
// contains the raw protocol message including any extension data.
|
||||
// Input: Remote -> [ChannelResult] -> {Client}
|
||||
// Output: {Client} -> [Proof] -> Remote
|
||||
func (ah *HiddenServiceAuthChannel) OpenOutboundResult(err error, crm *Protocol_Data_Control.ChannelResult) {
|
||||
|
||||
if err == nil {
|
||||
|
||||
if crm.GetOpened() {
|
||||
serverCookie, _ := proto.GetExtension(crm, Protocol_Data_AuthHiddenService.E_ServerCookie)
|
||||
|
||||
if len(serverCookie.([]byte)[:]) != 16 {
|
||||
ah.channel.SendMessage([]byte{})
|
||||
return
|
||||
}
|
||||
|
||||
ah.AddServerCookie(serverCookie.([]byte)[:])
|
||||
|
||||
challenge := ah.GenChallenge(ah.Identity.Hostname(), ah.ServerHostname)
|
||||
|
||||
signature, err := ah.Identity.Sign(challenge)
|
||||
|
||||
if err != nil {
|
||||
ah.channel.SendMessage([]byte{})
|
||||
return
|
||||
}
|
||||
|
||||
messageBuilder := new(utils.MessageBuilder)
|
||||
proof := messageBuilder.Proof(ah.Identity.PublicKeyBytes(), signature)
|
||||
ah.channel.SendMessage(proof)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Packet is called for each raw packet received on this channel.
|
||||
// Input: Client -> [Proof] -> Remote
|
||||
// OR
|
||||
// Input: Remote -> [Result] -> Client
|
||||
func (ah *HiddenServiceAuthChannel) Packet(data []byte) {
|
||||
res := new(Protocol_Data_AuthHiddenService.Packet)
|
||||
err := proto.Unmarshal(data[:], res)
|
||||
|
||||
if err != nil {
|
||||
ah.channel.CloseChannel()
|
||||
return
|
||||
}
|
||||
|
||||
if res.GetProof() != nil && ah.channel.Direction == Inbound {
|
||||
provisionalClientHostname := utils.GetTorHostname(res.GetProof().GetPublicKey())
|
||||
|
||||
if err != nil {
|
||||
ah.ServerAuthInvalid(err)
|
||||
ah.channel.SendMessage([]byte{})
|
||||
return
|
||||
}
|
||||
|
||||
serverHostname := ah.Identity.Hostname()
|
||||
|
||||
publicKey := rsa.PublicKey{}
|
||||
_, err = asn1.Unmarshal(res.GetProof().GetPublicKey(), &publicKey)
|
||||
if err != nil {
|
||||
ah.ServerAuthInvalid(err)
|
||||
ah.channel.SendMessage([]byte{})
|
||||
return
|
||||
}
|
||||
|
||||
challenge := ah.GenChallenge(provisionalClientHostname, serverHostname)
|
||||
|
||||
err = rsa.VerifyPKCS1v15(&publicKey, crypto.SHA256, challenge[:], res.GetProof().GetSignature())
|
||||
|
||||
if err == nil {
|
||||
// Signature is Good
|
||||
accepted, isKnownContact := ah.ServerAuthValid(provisionalClientHostname, publicKey)
|
||||
|
||||
// Send Result
|
||||
messageBuilder := new(utils.MessageBuilder)
|
||||
result := messageBuilder.AuthResult(accepted, isKnownContact)
|
||||
ah.channel.DelegateAuthorization()
|
||||
ah.channel.SendMessage(result)
|
||||
} else {
|
||||
// Auth Failed
|
||||
messageBuilder := new(utils.MessageBuilder)
|
||||
result := messageBuilder.AuthResult(false, false)
|
||||
ah.channel.SendMessage(result)
|
||||
ah.ServerAuthInvalid(err)
|
||||
}
|
||||
|
||||
} else if res.GetResult() != nil && ah.channel.Direction == Outbound {
|
||||
if ah.ClientAuthResult != nil {
|
||||
ah.ClientAuthResult(res.GetResult().GetAccepted(), res.GetResult().GetIsKnownContact())
|
||||
}
|
||||
if res.GetResult().GetAccepted() {
|
||||
ah.channel.DelegateAuthorization()
|
||||
}
|
||||
}
|
||||
|
||||
// Any other combination of packets is completely invalid
|
||||
// Fail the Authorization right here.
|
||||
ah.channel.CloseChannel()
|
||||
}
|
||||
|
||||
// AddClientCookie adds a client cookie to the state.
|
||||
func (ah *HiddenServiceAuthChannel) AddClientCookie(cookie []byte) {
|
||||
copy(ah.clientCookie[:], cookie[:16])
|
||||
}
|
||||
|
||||
// AddServerCookie adds a server cookie to the state.
|
||||
func (ah *HiddenServiceAuthChannel) AddServerCookie(cookie []byte) {
|
||||
copy(ah.serverCookie[:], cookie[:16])
|
||||
}
|
||||
|
||||
// GenRandom generates a random 16byte cookie string.
|
||||
func (ah *HiddenServiceAuthChannel) GenRandom() [16]byte {
|
||||
var cookie [16]byte
|
||||
io.ReadFull(rand.Reader, cookie[:])
|
||||
return cookie
|
||||
}
|
||||
|
||||
// GenClientCookie generates and adds a client cookie to the state.
|
||||
func (ah *HiddenServiceAuthChannel) GenClientCookie() [16]byte {
|
||||
ah.clientCookie = ah.GenRandom()
|
||||
return ah.clientCookie
|
||||
}
|
||||
|
||||
// GenServerCookie generates and adds a server cookie to the state.
|
||||
func (ah *HiddenServiceAuthChannel) GenServerCookie() [16]byte {
|
||||
ah.serverCookie = ah.GenRandom()
|
||||
return ah.serverCookie
|
||||
}
|
||||
|
||||
// GenChallenge constructs the challenge parameter for the AuthHiddenService session.
|
||||
// The challenge is the a Sha256HMAC(clientHostname+serverHostname, key=clientCookie+serverCookie)
|
||||
func (ah *HiddenServiceAuthChannel) GenChallenge(clientHostname string, serverHostname string) []byte {
|
||||
key := make([]byte, 32)
|
||||
copy(key[0:16], ah.clientCookie[:])
|
||||
copy(key[16:], ah.serverCookie[:])
|
||||
|
||||
value := []byte(clientHostname + serverHostname)
|
||||
mac := hmac.New(sha256.New, key)
|
||||
mac.Write(value)
|
||||
hmac := mac.Sum(nil)
|
||||
return hmac
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
package channels
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/wire/control"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenChallenge(t *testing.T) {
|
||||
authHandler := new(HiddenServiceAuthChannel)
|
||||
authHandler.AddClientCookie([]byte("abcdefghijklmnop"))
|
||||
authHandler.AddServerCookie([]byte("qrstuvwxyz012345"))
|
||||
challenge := authHandler.GenChallenge("test.onion", "notareal.onion")
|
||||
expectedChallenge := []byte{0xf5, 0xdb, 0xfd, 0xf0, 0x3d, 0x94, 0x14, 0xf1, 0x4b, 0x37, 0x93, 0xe2, 0xa5, 0x11, 0x4a, 0x98, 0x31, 0x90, 0xea, 0xb8, 0x95, 0x7a, 0x2e, 0xaa, 0xd0, 0xd2, 0x0c, 0x74, 0x95, 0xba, 0xab, 0x73}
|
||||
t.Log(challenge, expectedChallenge)
|
||||
if bytes.Compare(challenge[:], expectedChallenge[:]) != 0 {
|
||||
t.Errorf("HiddenServiceAuthChannel Challenge Is Invalid, Got %x, Expected %x", challenge, expectedChallenge)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenClientCookie(t *testing.T) {
|
||||
authHandler := new(HiddenServiceAuthChannel)
|
||||
clientCookie := authHandler.GenClientCookie()
|
||||
if clientCookie != authHandler.clientCookie {
|
||||
t.Errorf("HiddenServiceAuthChannel Client Cookies are Different %x %x", clientCookie, authHandler.clientCookie)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenServerCookie(t *testing.T) {
|
||||
authHandler := new(HiddenServiceAuthChannel)
|
||||
serverCookie := authHandler.GenServerCookie()
|
||||
if serverCookie != authHandler.serverCookie {
|
||||
t.Errorf("HiddenServiceAuthChannel Server Cookies are Different %x %x", serverCookie, authHandler.serverCookie)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHiddenServiceAuthChannelOptions(t *testing.T) {
|
||||
hiddenServiceAuthChannel := new(HiddenServiceAuthChannel)
|
||||
|
||||
if hiddenServiceAuthChannel.Type() != "im.ricochet.auth.hidden-service" {
|
||||
t.Errorf("AuthHiddenService has wrong type %s", hiddenServiceAuthChannel.Type())
|
||||
}
|
||||
|
||||
if !hiddenServiceAuthChannel.OnlyClientCanOpen() {
|
||||
t.Errorf("AuthHiddenService Should be Client Open Only")
|
||||
}
|
||||
if !hiddenServiceAuthChannel.Singleton() {
|
||||
t.Errorf("AuthHiddenService Should be a Singelton")
|
||||
}
|
||||
if hiddenServiceAuthChannel.Bidirectional() {
|
||||
t.Errorf("AuthHiddenService Should not be bidirectional")
|
||||
}
|
||||
if hiddenServiceAuthChannel.RequiresAuthentication() != "none" {
|
||||
t.Errorf("AuthHiddenService should require no authorization. Instead requires: %s", hiddenServiceAuthChannel.RequiresAuthentication())
|
||||
}
|
||||
}
|
||||
|
||||
func GetOpenAuthenticationChannelMessage() *Protocol_Data_Control.OpenChannel {
|
||||
// Construct the Open Authentication Channel Message
|
||||
messageBuilder := new(utils.MessageBuilder)
|
||||
ocm := messageBuilder.OpenAuthenticationChannel(1, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
|
||||
// We have just constructed this so there is little
|
||||
// point in doing error checking here in the test
|
||||
res := new(Protocol_Data_Control.Packet)
|
||||
proto.Unmarshal(ocm[:], res)
|
||||
return res.GetOpenChannel()
|
||||
}
|
||||
|
||||
func TestAuthenticationOpenInbound(t *testing.T) {
|
||||
id := identity.Init("../testing/private_key")
|
||||
opm := GetOpenAuthenticationChannelMessage()
|
||||
authHandler := new(HiddenServiceAuthChannel)
|
||||
authHandler.Identity = id
|
||||
channel := Channel{ID: 1}
|
||||
response, err := authHandler.OpenInbound(&channel, opm)
|
||||
|
||||
if err == nil {
|
||||
res := new(Protocol_Data_Control.Packet)
|
||||
proto.Unmarshal(response[:], res)
|
||||
|
||||
if res.GetChannelResult() == nil || !res.GetChannelResult().GetOpened() {
|
||||
t.Errorf("Response not a Open Channel Result %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("HiddenServiceAuthChannel OpenInbound Failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticationOpenOutbound(t *testing.T) {
|
||||
id := identity.Init("../testing/private_key")
|
||||
authHandler := new(HiddenServiceAuthChannel)
|
||||
authHandler.Identity = id
|
||||
authHandler.ServerHostname = "kwke2hntvyfqm7dr"
|
||||
channel := Channel{ID: 1}
|
||||
response, err := authHandler.OpenOutbound(&channel)
|
||||
|
||||
if err == nil {
|
||||
res := new(Protocol_Data_Control.Packet)
|
||||
proto.Unmarshal(response[:], res)
|
||||
|
||||
if res.GetOpenChannel() == nil {
|
||||
t.Errorf("Open Channel Packet not included %v", res)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("HiddenServiceAuthChannel OpenOutbound Failed: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAuthenticationOpenOutboundResult(t *testing.T) {
|
||||
|
||||
id := identity.Init("../testing/private_key")
|
||||
|
||||
authHandlerA := new(HiddenServiceAuthChannel)
|
||||
authHandlerB := new(HiddenServiceAuthChannel)
|
||||
|
||||
authHandlerA.Identity = id
|
||||
authHandlerA.ServerHostname = "kwke2hntvyfqm7dr"
|
||||
authHandlerA.ClientAuthResult = func(accepted, known bool) {}
|
||||
channelA := Channel{ID: 1, Direction: Outbound}
|
||||
channelA.SendMessage = func(message []byte) {
|
||||
authHandlerB.Packet(message)
|
||||
}
|
||||
channelA.DelegateAuthorization = func() {}
|
||||
channelA.CloseChannel = func() {}
|
||||
response, _ := authHandlerA.OpenOutbound(&channelA)
|
||||
res := new(Protocol_Data_Control.Packet)
|
||||
proto.Unmarshal(response[:], res)
|
||||
|
||||
authHandlerB.Identity = id
|
||||
authHandlerB.ServerAuthValid = func(hostname string, publicKey rsa.PublicKey) (allowed, known bool) { return true, true }
|
||||
authHandlerB.ServerAuthInvalid = func(err error) { t.Error("server received invalid auth") }
|
||||
channelB := Channel{ID: 1, Direction: Inbound}
|
||||
channelB.SendMessage = func(message []byte) {
|
||||
authHandlerA.Packet(message)
|
||||
}
|
||||
channelB.DelegateAuthorization = func() {}
|
||||
channelB.CloseChannel = func() {}
|
||||
response, _ = authHandlerB.OpenInbound(&channelB, res.GetOpenChannel())
|
||||
res = new(Protocol_Data_Control.Packet)
|
||||
proto.Unmarshal(response[:], res)
|
||||
|
||||
authHandlerA.OpenOutboundResult(nil, res.GetChannelResult())
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@ package connection
|
|||
|
||||
import (
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/inbound"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/wire/control"
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
@ -12,24 +13,23 @@ import (
|
|||
func TestInit(t *testing.T) {
|
||||
ach := new(AutoConnectionHandler)
|
||||
ach.Init()
|
||||
ach.RegisterChannelHandler("im.ricochet.auth.hidden-service", func() channels.Handler {
|
||||
return &channels.HiddenServiceAuthChannel{}
|
||||
ach.RegisterChannelHandler("im.ricochet.auth.3dh", func() channels.Handler {
|
||||
return &inbound.Server3DHAuthChannel{}
|
||||
})
|
||||
|
||||
// Construct the Open Authentication Channel Message
|
||||
messageBuilder := new(utils.MessageBuilder)
|
||||
ocm := messageBuilder.OpenAuthenticationChannel(1, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
ocm := messageBuilder.Open3EDHAuthenticationChannel(1, [32]byte{}, [32]byte{})
|
||||
|
||||
// We have just constructed this so there is little
|
||||
// point in doing error checking here in the test
|
||||
res := new(Protocol_Data_Control.Packet)
|
||||
proto.Unmarshal(ocm[:], res)
|
||||
opm := res.GetOpenChannel()
|
||||
//ocmessage, _ := proto.Marshal(opm)
|
||||
handler, err := ach.OnOpenChannelRequest(opm.GetChannelType())
|
||||
|
||||
if err == nil {
|
||||
if handler.Type() != "im.ricochet.auth.hidden-service" {
|
||||
if handler.Type() != "im.ricochet.auth.3dh" {
|
||||
t.Errorf("Failed to authentication handler: %v", handler.Type())
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -21,36 +21,6 @@ func ServerAuthValid3DH(hostname string, publicKey ed25519.PublicKey) (allowed,
|
|||
return true, true
|
||||
}
|
||||
|
||||
func TestProcessAuthAsServer(t *testing.T) {
|
||||
|
||||
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
||||
|
||||
go func() {
|
||||
cconn, _ := net.Dial("tcp", ln.Addr().String())
|
||||
|
||||
orc := NewOutboundConnection(cconn, "kwke2hntvyfqm7dr")
|
||||
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key")
|
||||
|
||||
known, err := HandleOutboundConnection(orc).ProcessAuthAsClient(identity.Initialize("", privateKey))
|
||||
if err != nil {
|
||||
t.Errorf("Error while testing ProcessAuthAsClient (in ProcessAuthAsServer) %v", err)
|
||||
return
|
||||
} else if !known {
|
||||
t.Errorf("Client should have been known to the server, instead known was: %v", known)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
conn, _ := ln.Accept()
|
||||
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key")
|
||||
|
||||
rc := NewInboundConnection(conn)
|
||||
err := HandleInboundConnection(rc).ProcessAuthAsServer(identity.Initialize("", privateKey), ServerAuthValid)
|
||||
if err != nil {
|
||||
t.Errorf("Error while testing ProcessAuthAsServer: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessAuthAs3DHServer(t *testing.T) {
|
||||
|
||||
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
||||
|
@ -142,30 +112,6 @@ func TestProcessAuthAsV3ClientFail(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProcessServerAuthFail(t *testing.T) {
|
||||
|
||||
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
||||
|
||||
go func() {
|
||||
cconn, _ := net.Dial("tcp", ln.Addr().String())
|
||||
|
||||
orc := NewOutboundConnection(cconn, "kwke2hntvyfqm7dr")
|
||||
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key")
|
||||
|
||||
HandleOutboundConnection(orc).ProcessAuthAsClient(identity.Initialize("", privateKey))
|
||||
|
||||
}()
|
||||
|
||||
conn, _ := ln.Accept()
|
||||
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key_auth_fail_test")
|
||||
|
||||
rc := NewInboundConnection(conn)
|
||||
err := HandleInboundConnection(rc).ProcessAuthAsServer(identity.Initialize("", privateKey), ServerAuthValid)
|
||||
if err == nil {
|
||||
t.Errorf("Error while testing ProcessAuthAsServer - should have failed %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessAuthTimeout(t *testing.T) {
|
||||
|
||||
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
||||
|
@ -177,10 +123,10 @@ func TestProcessAuthTimeout(t *testing.T) {
|
|||
}()
|
||||
|
||||
conn, _ := ln.Accept()
|
||||
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key")
|
||||
|
||||
pub, priv, _ := ed25519.GenerateKey(rand.Reader)
|
||||
rc := NewInboundConnection(conn)
|
||||
err := HandleInboundConnection(rc).ProcessAuthAsServer(identity.Initialize("", privateKey), ServerAuthValid)
|
||||
err := HandleInboundConnection(rc).ProcessAuthAsV3Server(identity.InitializeV3("", &priv, &pub), ServerAuthValid3DH)
|
||||
if err != utils.ActionTimedOutError {
|
||||
t.Errorf("Error while testing TestProcessAuthTimeout - Should have timed out after 15 seconds, instead ERR was %v", err)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package connection
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/inbound"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||
|
@ -24,74 +23,6 @@ func HandleInboundConnection(c *Connection) *InboundConnectionHandler {
|
|||
return ich
|
||||
}
|
||||
|
||||
// ProcessAuthAsServer blocks until authentication has succeeded, failed, or the
|
||||
// connection is closed. A non-nil error is returned in all cases other than successful
|
||||
// and accepted authentication.
|
||||
//
|
||||
// ProcessAuthAsServer cannot be called at the same time as any other call to a Process
|
||||
// function. Another Process function must be called after this function successfully
|
||||
// returns to continue handling connection events.
|
||||
//
|
||||
// The acceptCallback function is called after receiving a valid authentication proof
|
||||
// with the client's authenticated hostname and public key. acceptCallback must return
|
||||
// true to accept authentication and allow the connection to continue, and also returns a
|
||||
// boolean indicating whether the contact is known and recognized. Unknown contacts will
|
||||
// assume they are required to send a contact request before any other activity.
|
||||
// TODO: Deprecate
|
||||
func (ich *InboundConnectionHandler) ProcessAuthAsServer(identity identity.Identity, sach func(hostname string, publicKey rsa.PublicKey) (allowed, known bool)) error {
|
||||
|
||||
if !identity.Initialized() {
|
||||
return utils.PrivateKeyNotSetError
|
||||
}
|
||||
|
||||
var breakOnce sync.Once
|
||||
|
||||
var authAllowed, authKnown bool
|
||||
var authHostname string
|
||||
|
||||
onAuthValid := func(hostname string, publicKey rsa.PublicKey) (allowed, known bool) {
|
||||
authAllowed, authKnown = sach(hostname, publicKey)
|
||||
if authAllowed {
|
||||
authHostname = hostname
|
||||
}
|
||||
breakOnce.Do(func() { go ich.connection.Break() })
|
||||
return authAllowed, authKnown
|
||||
}
|
||||
onAuthInvalid := func(err error) {
|
||||
// err is ignored at the moment
|
||||
breakOnce.Do(func() { go ich.connection.Break() })
|
||||
}
|
||||
|
||||
ach := new(AutoConnectionHandler)
|
||||
ach.Init()
|
||||
ach.RegisterChannelHandler("im.ricochet.auth.hidden-service",
|
||||
func() channels.Handler {
|
||||
return &channels.HiddenServiceAuthChannel{
|
||||
Identity: identity,
|
||||
ServerAuthValid: onAuthValid,
|
||||
ServerAuthInvalid: onAuthInvalid,
|
||||
}
|
||||
})
|
||||
|
||||
// Ensure that the call to Process() cannot outlive this function,
|
||||
// particularly for the case where the policy timeout expires
|
||||
defer breakOnce.Do(func() { ich.connection.Break() })
|
||||
policy := policies.UnknownPurposeTimeout
|
||||
err := policy.ExecuteAction(func() error {
|
||||
return ich.connection.Process(ach)
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
if authAllowed == true {
|
||||
ich.connection.RemoteHostname = authHostname
|
||||
return nil
|
||||
}
|
||||
return utils.ClientFailedToAuthenticateError
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ProcessAuthAsV3Server blocks until authentication has succeeded, failed, or the
|
||||
// connection is closed. A non-nil error is returned in all cases other than successful
|
||||
// and accepted authentication.
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package connection
|
||||
|
||||
import (
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/outbound"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||
"git.openprivacy.ca/openprivacy/libricochet-go/policies"
|
||||
|
@ -22,75 +21,6 @@ func HandleOutboundConnection(c *Connection) *OutboundConnectionHandler {
|
|||
return och
|
||||
}
|
||||
|
||||
// ProcessAuthAsClient blocks until authentication has succeeded or failed with the
|
||||
// provided identity, or the connection is closed. A non-nil error is returned in all
|
||||
// cases other than successful authentication.
|
||||
//
|
||||
// ProcessAuthAsClient cannot be called at the same time as any other call to a Porcess
|
||||
// function. Another Process function must be called after this function successfully
|
||||
// returns to continue handling connection events.
|
||||
//
|
||||
// For successful authentication, the `known` return value indicates whether the peer
|
||||
// accepts us as a known contact. Unknown contacts will generally need to send a contact
|
||||
// request before any other activity.
|
||||
// TODO; Deprecate
|
||||
func (och *OutboundConnectionHandler) ProcessAuthAsClient(identity identity.Identity) (bool, error) {
|
||||
|
||||
if !identity.Initialized() {
|
||||
return false, utils.PrivateKeyNotSetError
|
||||
}
|
||||
|
||||
ach := new(AutoConnectionHandler)
|
||||
ach.Init()
|
||||
|
||||
// Make sure that calls to Break in this function cannot race
|
||||
var breakOnce sync.Once
|
||||
|
||||
var accepted, isKnownContact bool
|
||||
authCallback := func(accept, known bool) {
|
||||
accepted = accept
|
||||
isKnownContact = known
|
||||
// Cause the Process() call below to return.
|
||||
// If Break() is called from here, it _must_ use go, because this will
|
||||
// execute in the Process goroutine, and Break() will deadlock.
|
||||
breakOnce.Do(func() { go och.connection.Break() })
|
||||
}
|
||||
|
||||
processResult := make(chan error, 1)
|
||||
go func() {
|
||||
// Break Process() if timed out; no-op if Process returned a conn error
|
||||
defer func() { breakOnce.Do(func() { och.connection.Break() }) }()
|
||||
policy := policies.UnknownPurposeTimeout
|
||||
err := policy.ExecuteAction(func() error {
|
||||
return och.connection.Process(ach)
|
||||
})
|
||||
processResult <- err
|
||||
}()
|
||||
|
||||
err := och.connection.Do(func() error {
|
||||
_, err := och.connection.RequestOpenChannel("im.ricochet.auth.hidden-service",
|
||||
&channels.HiddenServiceAuthChannel{
|
||||
Identity: identity,
|
||||
ServerHostname: och.connection.RemoteHostname,
|
||||
ClientAuthResult: authCallback,
|
||||
})
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
breakOnce.Do(func() { och.connection.Break() })
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err = <-processResult; err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if accepted == true {
|
||||
return isKnownContact, nil
|
||||
}
|
||||
return false, utils.ServerRejectedClientConnectionError
|
||||
}
|
||||
|
||||
// ProcessAuthAsV3Client blocks until authentication has succeeded or failed with the
|
||||
// provided identity, or the connection is closed. A non-nil error is returned in all
|
||||
// cases other than successful authentication.
|
||||
|
|
|
@ -16,7 +16,7 @@ func TestNegotiateInboundVersions(t *testing.T) {
|
|||
}
|
||||
defer conn.Close()
|
||||
|
||||
conn.Write([]byte{0x49, 0x4D, 0x01, 0x01})
|
||||
conn.Write([]byte{0x49, 0x4D, 0x01, 0x03})
|
||||
}
|
||||
|
||||
l, err := net.Listen("tcp", ":4000")
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestOutboundVersionNegotiation(t *testing.T) {
|
|||
b := make([]byte, 4)
|
||||
n, err := conn.Read(b)
|
||||
if n == 4 && err == nil {
|
||||
conn.Write([]byte{0x01})
|
||||
conn.Write([]byte{0x03})
|
||||
}
|
||||
conn.Close()
|
||||
}()
|
||||
|
|
|
@ -31,7 +31,7 @@ func Open(acn connectivity.ACN, remoteHostname string) (*connection.Connection,
|
|||
// NegotiateVersionOutbound takes an open network connection and executes
|
||||
// the ricochet version negotiation procedure.
|
||||
func NegotiateVersionOutbound(conn net.Conn, remoteHostname string) (*connection.Connection, error) {
|
||||
versions := []byte{0x49, 0x4D, 0x01, 0x01}
|
||||
versions := []byte{0x49, 0x4D, 0x01, 0x03}
|
||||
if n, err := conn.Write(versions); err != nil || n < len(versions) {
|
||||
return nil, utils.VersionNegotiationError
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func NegotiateVersionOutbound(conn net.Conn, remoteHostname string) (*connection
|
|||
return nil, utils.VersionNegotiationError
|
||||
}
|
||||
|
||||
if res[0] != 0x01 {
|
||||
if res[0] != 0x03 {
|
||||
return nil, utils.VersionNegotiationFailed
|
||||
}
|
||||
rc := connection.NewOutboundConnection(conn, remoteHostname)
|
||||
|
@ -52,7 +52,7 @@ func NegotiateVersionOutbound(conn net.Conn, remoteHostname string) (*connection
|
|||
// 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}
|
||||
versions := []byte{0x49, 0x4D, 0x01, 0x03}
|
||||
// Read version response header
|
||||
header := make([]byte, 3)
|
||||
if _, err := io.ReadAtLeast(conn, header, len(header)); err != nil {
|
||||
|
@ -71,7 +71,7 @@ func NegotiateVersionInbound(conn net.Conn) (*connection.Connection, error) {
|
|||
|
||||
selectedVersion := byte(0xff)
|
||||
for _, v := range versionList {
|
||||
if v == 0x01 {
|
||||
if v == 0x03 {
|
||||
selectedVersion = v
|
||||
break
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ func SimpleServer() {
|
|||
b := make([]byte, 4)
|
||||
n, err := conn.Read(b)
|
||||
if n == 4 && err == nil {
|
||||
conn.Write([]byte{0x01})
|
||||
conn.Write([]byte{0x03})
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue