Delete last reminants of V2 Onion Handling
This commit is contained in:
parent
64ce11d436
commit
7a4350f0c1
|
@ -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 (
|
import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"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/utils"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/wire/control"
|
"git.openprivacy.ca/openprivacy/libricochet-go/wire/control"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
@ -12,24 +13,23 @@ import (
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
ach := new(AutoConnectionHandler)
|
ach := new(AutoConnectionHandler)
|
||||||
ach.Init()
|
ach.Init()
|
||||||
ach.RegisterChannelHandler("im.ricochet.auth.hidden-service", func() channels.Handler {
|
ach.RegisterChannelHandler("im.ricochet.auth.3dh", func() channels.Handler {
|
||||||
return &channels.HiddenServiceAuthChannel{}
|
return &inbound.Server3DHAuthChannel{}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Construct the Open Authentication Channel Message
|
// Construct the Open Authentication Channel Message
|
||||||
messageBuilder := new(utils.MessageBuilder)
|
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
|
// We have just constructed this so there is little
|
||||||
// point in doing error checking here in the test
|
// point in doing error checking here in the test
|
||||||
res := new(Protocol_Data_Control.Packet)
|
res := new(Protocol_Data_Control.Packet)
|
||||||
proto.Unmarshal(ocm[:], res)
|
proto.Unmarshal(ocm[:], res)
|
||||||
opm := res.GetOpenChannel()
|
opm := res.GetOpenChannel()
|
||||||
//ocmessage, _ := proto.Marshal(opm)
|
|
||||||
handler, err := ach.OnOpenChannelRequest(opm.GetChannelType())
|
handler, err := ach.OnOpenChannelRequest(opm.GetChannelType())
|
||||||
|
|
||||||
if err == nil {
|
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())
|
t.Errorf("Failed to authentication handler: %v", handler.Type())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,36 +21,6 @@ func ServerAuthValid3DH(hostname string, publicKey ed25519.PublicKey) (allowed,
|
||||||
return true, true
|
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) {
|
func TestProcessAuthAs3DHServer(t *testing.T) {
|
||||||
|
|
||||||
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
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) {
|
func TestProcessAuthTimeout(t *testing.T) {
|
||||||
|
|
||||||
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
@ -177,10 +123,10 @@ func TestProcessAuthTimeout(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
conn, _ := ln.Accept()
|
conn, _ := ln.Accept()
|
||||||
privateKey, _ := utils.LoadPrivateKeyFromFile("../testing/private_key")
|
// Giving the client inconsistent keypair to make EDH fail
|
||||||
|
pub, priv, _ := ed25519.GenerateKey(rand.Reader)
|
||||||
rc := NewInboundConnection(conn)
|
rc := NewInboundConnection(conn)
|
||||||
err := HandleInboundConnection(rc).ProcessAuthAsServer(identity.Initialize("", privateKey), ServerAuthValid)
|
err := HandleInboundConnection(rc).ProcessAuthAsV3Server(identity.InitializeV3("", &priv, &pub), ServerAuthValid3DH)
|
||||||
if err != utils.ActionTimedOutError {
|
if err != utils.ActionTimedOutError {
|
||||||
t.Errorf("Error while testing TestProcessAuthTimeout - Should have timed out after 15 seconds, instead ERR was %v", err)
|
t.Errorf("Error while testing TestProcessAuthTimeout - Should have timed out after 15 seconds, instead ERR was %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package connection
|
package connection
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rsa"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/inbound"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/inbound"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
|
@ -24,74 +23,6 @@ func HandleInboundConnection(c *Connection) *InboundConnectionHandler {
|
||||||
return ich
|
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
|
// ProcessAuthAsV3Server blocks until authentication has succeeded, failed, or the
|
||||||
// connection is closed. A non-nil error is returned in all cases other than successful
|
// connection is closed. A non-nil error is returned in all cases other than successful
|
||||||
// and accepted authentication.
|
// and accepted authentication.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package connection
|
package connection
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/outbound"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels/v3/outbound"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/policies"
|
"git.openprivacy.ca/openprivacy/libricochet-go/policies"
|
||||||
|
@ -22,75 +21,6 @@ func HandleOutboundConnection(c *Connection) *OutboundConnectionHandler {
|
||||||
return och
|
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
|
// 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
|
// provided identity, or the connection is closed. A non-nil error is returned in all
|
||||||
// cases other than successful authentication.
|
// cases other than successful authentication.
|
||||||
|
|
Reference in New Issue