@ -1,6 +1,8 @@
|
|||||||
package eap
|
package eap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
||||||
"layeh.com/radius"
|
"layeh.com/radius"
|
||||||
@ -12,6 +14,7 @@ type context struct {
|
|||||||
typeState map[protocol.Type]any
|
typeState map[protocol.Type]any
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
settings interface{}
|
settings interface{}
|
||||||
|
parent *context
|
||||||
endStatus protocol.Status
|
endStatus protocol.Status
|
||||||
endModifier func(p *radius.Packet) *radius.Packet
|
endModifier func(p *radius.Packet) *radius.Packet
|
||||||
handleInner func(protocol.Payload, protocol.StateManager) (protocol.Payload, error)
|
handleInner func(protocol.Payload, protocol.StateManager) (protocol.Payload, error)
|
||||||
@ -27,19 +30,23 @@ func (ctx *context) Log() *log.Entry { return ctx.log }
|
|||||||
func (ctx *context) HandleInnerEAP(p protocol.Payload, st protocol.StateManager) (protocol.Payload, error) {
|
func (ctx *context) HandleInnerEAP(p protocol.Payload, st protocol.StateManager) (protocol.Payload, error) {
|
||||||
return ctx.handleInner(p, st)
|
return ctx.handleInner(p, st)
|
||||||
}
|
}
|
||||||
|
func (ctx *context) Inner(p protocol.Payload, t protocol.Type) protocol.Context {
|
||||||
func (ctx *context) ForInnerProtocol(p protocol.Type) protocol.Context {
|
|
||||||
return &context{
|
return &context{
|
||||||
req: ctx.req,
|
req: ctx.req,
|
||||||
|
rootPayload: ctx.rootPayload,
|
||||||
typeState: ctx.typeState,
|
typeState: ctx.typeState,
|
||||||
log: ctx.log,
|
log: ctx.log.WithField("type", fmt.Sprintf("%T", p)).WithField("code", t),
|
||||||
settings: ctx.settings,
|
settings: ctx.settings,
|
||||||
endStatus: ctx.endStatus,
|
parent: ctx,
|
||||||
endModifier: ctx.endModifier,
|
handleInner: ctx.handleInner,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *context) EndInnerProtocol(st protocol.Status, mf func(p *radius.Packet) *radius.Packet) {
|
func (ctx *context) EndInnerProtocol(st protocol.Status, mf func(p *radius.Packet) *radius.Packet) {
|
||||||
|
ctx.log.Info("Ending protocol")
|
||||||
|
if ctx.parent != nil {
|
||||||
|
ctx.parent.EndInnerProtocol(st, mf)
|
||||||
|
return
|
||||||
|
}
|
||||||
if ctx.endStatus != protocol.StatusUnknown {
|
if ctx.endStatus != protocol.StatusUnknown {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -51,3 +58,13 @@ func (ctx *context) EndInnerProtocol(st protocol.Status, mf func(p *radius.Packe
|
|||||||
}
|
}
|
||||||
ctx.endModifier = mf
|
ctx.endModifier = mf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *context) callEndModifier(p *radius.Packet) *radius.Packet {
|
||||||
|
if ctx.parent != nil {
|
||||||
|
p = ctx.parent.callEndModifier(p)
|
||||||
|
}
|
||||||
|
if ctx.endModifier != nil {
|
||||||
|
p = ctx.endModifier(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
@ -34,7 +34,7 @@ func (p *Packet) HandleRadiusPacket(w radius.ResponseWriter, r *radius.Request)
|
|||||||
p.state = rst
|
p.state = rst
|
||||||
|
|
||||||
rp := &Packet{r: r}
|
rp := &Packet{r: r}
|
||||||
rep, err := p.handleEAP(p.eap, p.stm)
|
rep, err := p.handleEAP(p.eap, p.stm, nil)
|
||||||
rp.eap = rep
|
rp.eap = rep
|
||||||
|
|
||||||
rres := r.Response(radius.CodeAccessReject)
|
rres := r.Response(radius.CodeAccessReject)
|
||||||
@ -74,7 +74,7 @@ func (p *Packet) HandleRadiusPacket(w radius.ResponseWriter, r *radius.Request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Packet) handleEAP(pp protocol.Payload, stm protocol.StateManager) (*eap.Payload, error) {
|
func (p *Packet) handleEAP(pp protocol.Payload, stm protocol.StateManager, parentContext *context) (*eap.Payload, error) {
|
||||||
st := stm.GetEAPState(p.state)
|
st := stm.GetEAPState(p.state)
|
||||||
if st == nil {
|
if st == nil {
|
||||||
log.Debug("Root-EAP: blank state")
|
log.Debug("Root-EAP: blank state")
|
||||||
@ -93,7 +93,7 @@ func (p *Packet) handleEAP(pp protocol.Payload, stm protocol.StateManager) (*eap
|
|||||||
st.ProtocolIndex += 1
|
st.ProtocolIndex += 1
|
||||||
st.TypeState = map[protocol.Type]any{}
|
st.TypeState = map[protocol.Type]any{}
|
||||||
stm.SetEAPState(p.state, st)
|
stm.SetEAPState(p.state, st)
|
||||||
return p.handleEAP(pp, stm)
|
return p.handleEAP(pp, stm, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if n, ok := p.eap.Payload.(*legacy_nak.Payload); ok {
|
if n, ok := p.eap.Payload.(*legacy_nak.Payload); ok {
|
||||||
@ -104,21 +104,26 @@ func (p *Packet) handleEAP(pp protocol.Payload, stm protocol.StateManager) (*eap
|
|||||||
|
|
||||||
np, t, _ := eap.EmptyPayload(stm.GetEAPSettings(), nextChallengeToOffer)
|
np, t, _ := eap.EmptyPayload(stm.GetEAPSettings(), nextChallengeToOffer)
|
||||||
|
|
||||||
ctx := &context{
|
var ctx *context
|
||||||
req: p.r,
|
if parentContext != nil {
|
||||||
rootPayload: p.eap,
|
ctx = parentContext.Inner(np, t).(*context)
|
||||||
typeState: st.TypeState,
|
} else {
|
||||||
log: log.WithField("type", fmt.Sprintf("%T", np)).WithField("code", t),
|
ctx = &context{
|
||||||
settings: stm.GetEAPSettings().ProtocolSettings[t],
|
req: p.r,
|
||||||
handleInner: func(pp protocol.Payload, sm protocol.StateManager) (protocol.Payload, error) {
|
rootPayload: p.eap,
|
||||||
return p.handleEAP(pp, sm)
|
typeState: st.TypeState,
|
||||||
},
|
log: log.WithField("type", fmt.Sprintf("%T", np)).WithField("code", t),
|
||||||
|
settings: stm.GetEAPSettings().ProtocolSettings[t],
|
||||||
|
}
|
||||||
|
ctx.handleInner = func(pp protocol.Payload, sm protocol.StateManager) (protocol.Payload, error) {
|
||||||
|
return p.handleEAP(pp, sm, ctx.Inner(pp, pp.Type()).(*context))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !np.Offerable() {
|
if !np.Offerable() {
|
||||||
ctx.log.Debug("Root-EAP: protocol not offerable, skipping")
|
ctx.Log().Debug("Root-EAP: protocol not offerable, skipping")
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
ctx.log.Debug("Root-EAP: Passing to protocol")
|
ctx.Log().Debug("Root-EAP: Passing to protocol")
|
||||||
|
|
||||||
res := &eap.Payload{
|
res := &eap.Payload{
|
||||||
Code: protocol.CodeRequest,
|
Code: protocol.CodeRequest,
|
||||||
@ -137,7 +142,7 @@ func (p *Packet) handleEAP(pp protocol.Payload, stm protocol.StateManager) (*eap
|
|||||||
stm.SetEAPState(p.state, st)
|
stm.SetEAPState(p.state, st)
|
||||||
|
|
||||||
if ctx.endModifier != nil {
|
if ctx.endModifier != nil {
|
||||||
p.endModifier = ctx.endModifier
|
p.endModifier = ctx.callEndModifier
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ctx.endStatus {
|
switch ctx.endStatus {
|
||||||
|
@ -25,6 +25,7 @@ type Context interface {
|
|||||||
IsProtocolStart(p Type) bool
|
IsProtocolStart(p Type) bool
|
||||||
|
|
||||||
HandleInnerEAP(Payload, StateManager) (Payload, error)
|
HandleInnerEAP(Payload, StateManager) (Payload, error)
|
||||||
|
Inner(Payload, Type) Context
|
||||||
EndInnerProtocol(Status, func(p *radius.Packet) *radius.Packet)
|
EndInnerProtocol(Status, func(p *radius.Packet) *radius.Packet)
|
||||||
|
|
||||||
Log() *log.Entry
|
Log() *log.Entry
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"layeh.com/radius/rfc2759"
|
"layeh.com/radius/rfc2759"
|
||||||
|
"layeh.com/radius/rfc3079"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Payload) checkChapPassword(res *Response) ([]byte, error) {
|
func (p *Payload) checkChapPassword(res *Response) ([]byte, error) {
|
||||||
@ -18,6 +19,17 @@ func (p *Payload) checkChapPassword(res *Response) ([]byte, error) {
|
|||||||
if !bytes.Equal(ntResponse, res.NTResponse) {
|
if !bytes.Equal(ntResponse, res.NTResponse) {
|
||||||
return nil, errors.New("nt response mismatch")
|
return nil, errors.New("nt response mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.st.recvKey, err = rfc3079.MakeKey(ntResponse, bytePwd, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.st.sendKey, err = rfc3079.MakeKey(ntResponse, bytePwd, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
authenticatorResponse, err := rfc2759.GenerateAuthenticatorResponse(p.st.Challenge, p.st.PeerChallenge, ntResponse, byteUser, bytePwd)
|
authenticatorResponse, err := rfc2759.GenerateAuthenticatorResponse(p.st.Challenge, p.st.PeerChallenge, ntResponse, byteUser, bytePwd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
||||||
"goauthentik.io/internal/outpost/radius/eap/protocol/eap"
|
"goauthentik.io/internal/outpost/radius/eap/protocol/eap"
|
||||||
"goauthentik.io/internal/outpost/radius/eap/protocol/peap"
|
"goauthentik.io/internal/outpost/radius/eap/protocol/peap"
|
||||||
|
"layeh.com/radius"
|
||||||
|
"layeh.com/radius/vendors/microsoft"
|
||||||
)
|
)
|
||||||
|
|
||||||
const TypeMSCHAPv2 protocol.Type = 26
|
const TypeMSCHAPv2 protocol.Type = 26
|
||||||
@ -63,7 +65,7 @@ func (p *Payload) Decode(raw []byte) error {
|
|||||||
|
|
||||||
p.ValueSize = raw[4]
|
p.ValueSize = raw[4]
|
||||||
if p.ValueSize != responseValueSize {
|
if p.ValueSize != responseValueSize {
|
||||||
return fmt.Errorf("mschapv2: incorrect value size: %d", p.ValueSize)
|
return fmt.Errorf("MSCHAPv2: incorrect value size: %d", p.ValueSize)
|
||||||
}
|
}
|
||||||
p.Response = raw[5 : p.ValueSize+5]
|
p.Response = raw[5 : p.ValueSize+5]
|
||||||
p.Name = raw[5+p.ValueSize:]
|
p.Name = raw[5+p.ValueSize:]
|
||||||
@ -136,7 +138,7 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
|
|||||||
}
|
}
|
||||||
return succ
|
return succ
|
||||||
} else if p.OpCode == OpSuccess && p.st.Authenticated {
|
} else if p.OpCode == OpSuccess && p.st.Authenticated {
|
||||||
return &peap.ExtensionPayload{
|
ep := &peap.ExtensionPayload{
|
||||||
AVPs: []peap.ExtensionAVP{
|
AVPs: []peap.ExtensionAVP{
|
||||||
{
|
{
|
||||||
Mandatory: true,
|
Mandatory: true,
|
||||||
@ -145,6 +147,19 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
p.st.IsProtocolEnded = true
|
||||||
|
return ep
|
||||||
|
} else if p.st.IsProtocolEnded {
|
||||||
|
ctx.EndInnerProtocol(protocol.StatusSuccess, func(r *radius.Packet) *radius.Packet {
|
||||||
|
if len(microsoft.MSMPPERecvKey_Get(r, ctx.Packet().Packet)) < 1 {
|
||||||
|
microsoft.MSMPPERecvKey_Set(r, p.st.recvKey)
|
||||||
|
}
|
||||||
|
if len(microsoft.MSMPPESendKey_Get(r, ctx.Packet().Packet)) < 1 {
|
||||||
|
microsoft.MSMPPESendKey_Set(r, p.st.sendKey)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
})
|
||||||
|
return &Payload{}
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package mschapv2
|
package mschapv2
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
Challenge []byte
|
Challenge []byte
|
||||||
PeerChallenge []byte
|
PeerChallenge []byte
|
||||||
Authenticated bool
|
Authenticated bool
|
||||||
|
IsProtocolEnded bool
|
||||||
|
recvKey []byte
|
||||||
|
sendKey []byte
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"goauthentik.io/internal/outpost/radius/eap/debug"
|
||||||
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ type ExtensionPayload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ep *ExtensionPayload) Decode(raw []byte) error {
|
func (ep *ExtensionPayload) Decode(raw []byte) error {
|
||||||
|
log.WithField("raw", debug.FormatBytes(raw)).Debugf("PEAP-Extension: decode raw")
|
||||||
ep.AVPs = []ExtensionAVP{}
|
ep.AVPs = []ExtensionAVP{}
|
||||||
offset := 0
|
offset := 0
|
||||||
for {
|
for {
|
||||||
@ -32,7 +34,7 @@ func (ep *ExtensionPayload) Decode(raw []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ep *ExtensionPayload) Encode() ([]byte, error) {
|
func (ep *ExtensionPayload) Encode() ([]byte, error) {
|
||||||
log.Debug("PEAP: Extension encode")
|
log.Debug("PEAP-Extension: encode")
|
||||||
buff := []byte{}
|
buff := []byte{}
|
||||||
for _, avp := range ep.AVPs {
|
for _, avp := range ep.AVPs {
|
||||||
buff = append(buff, avp.Encode()...)
|
buff = append(buff, avp.Encode()...)
|
||||||
|
@ -51,7 +51,7 @@ func (p *Payload) Decode(raw []byte) error {
|
|||||||
func (p *Payload) Encode() ([]byte, error) {
|
func (p *Payload) Encode() ([]byte, error) {
|
||||||
log.Debug("PEAP: Encoding inner EAP")
|
log.Debug("PEAP: Encoding inner EAP")
|
||||||
if p.eap.Payload == nil {
|
if p.eap.Payload == nil {
|
||||||
return []byte{}, errors.New("peap: no payload in response eap packet")
|
return []byte{}, errors.New("PEAP: no payload in response eap packet")
|
||||||
}
|
}
|
||||||
payload, err := p.eap.Payload.Encode()
|
payload, err := p.eap.Payload.Encode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -129,6 +129,7 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
|
|||||||
res, err := ctx.HandleInnerEAP(ep, p)
|
res, err := ctx.HandleInnerEAP(ep, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Log().WithError(err).Warning("PEAP: failed to handle inner EAP")
|
ctx.Log().WithError(err).Warning("PEAP: failed to handle inner EAP")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// Normal payloads need to be wrapped in PEAP to use the correct encoding (see Encode() above)
|
// Normal payloads need to be wrapped in PEAP to use the correct encoding (see Encode() above)
|
||||||
// Extension payloads handle encoding differently
|
// Extension payloads handle encoding differently
|
||||||
|
@ -23,7 +23,7 @@ func (p *Payload) innerHandler(ctx protocol.Context) {
|
|||||||
ctx.EndInnerProtocol(protocol.StatusError, nil)
|
ctx.EndInnerProtocol(protocol.StatusError, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pl := p.Inner.Handle(ctx)
|
pl := p.Inner.Handle(ctx.Inner(p.Inner, p.Inner.Type()))
|
||||||
enc, err := pl.Encode()
|
enc, err := pl.Encode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Log().WithError(err).Warning("TLS: failed to encode inner protocol")
|
ctx.Log().WithError(err).Warning("TLS: failed to encode inner protocol")
|
||||||
|
@ -145,6 +145,7 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
|
|||||||
retry.Attempts(0),
|
retry.Attempts(0),
|
||||||
)
|
)
|
||||||
ctx.EndInnerProtocol(pst, func(r *radius.Packet) *radius.Packet {
|
ctx.EndInnerProtocol(pst, func(r *radius.Packet) *radius.Packet {
|
||||||
|
ctx.Log().Debug("TLS: Adding MPPE Keys")
|
||||||
microsoft.MSMPPERecvKey_Set(r, p.st.MPPEKey[:32])
|
microsoft.MSMPPERecvKey_Set(r, p.st.MPPEKey[:32])
|
||||||
microsoft.MSMPPESendKey_Set(r, p.st.MPPEKey[64:64+32])
|
microsoft.MSMPPESendKey_Set(r, p.st.MPPEKey[64:64+32])
|
||||||
return r
|
return r
|
||||||
|
Reference in New Issue
Block a user