@ -1,6 +1,8 @@
|
||||
package eap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
||||
"layeh.com/radius"
|
||||
@ -12,6 +14,7 @@ type context struct {
|
||||
typeState map[protocol.Type]any
|
||||
log *log.Entry
|
||||
settings interface{}
|
||||
parent *context
|
||||
endStatus protocol.Status
|
||||
endModifier func(p *radius.Packet) *radius.Packet
|
||||
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) {
|
||||
return ctx.handleInner(p, st)
|
||||
}
|
||||
|
||||
func (ctx *context) ForInnerProtocol(p protocol.Type) protocol.Context {
|
||||
func (ctx *context) Inner(p protocol.Payload, t protocol.Type) protocol.Context {
|
||||
return &context{
|
||||
req: ctx.req,
|
||||
rootPayload: ctx.rootPayload,
|
||||
typeState: ctx.typeState,
|
||||
log: ctx.log,
|
||||
log: ctx.log.WithField("type", fmt.Sprintf("%T", p)).WithField("code", t),
|
||||
settings: ctx.settings,
|
||||
endStatus: ctx.endStatus,
|
||||
endModifier: ctx.endModifier,
|
||||
parent: ctx,
|
||||
handleInner: ctx.handleInner,
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -51,3 +58,13 @@ func (ctx *context) EndInnerProtocol(st protocol.Status, mf func(p *radius.Packe
|
||||
}
|
||||
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
|
||||
|
||||
rp := &Packet{r: r}
|
||||
rep, err := p.handleEAP(p.eap, p.stm)
|
||||
rep, err := p.handleEAP(p.eap, p.stm, nil)
|
||||
rp.eap = rep
|
||||
|
||||
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)
|
||||
if st == nil {
|
||||
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.TypeState = map[protocol.Type]any{}
|
||||
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 {
|
||||
@ -104,21 +104,26 @@ func (p *Packet) handleEAP(pp protocol.Payload, stm protocol.StateManager) (*eap
|
||||
|
||||
np, t, _ := eap.EmptyPayload(stm.GetEAPSettings(), nextChallengeToOffer)
|
||||
|
||||
ctx := &context{
|
||||
req: p.r,
|
||||
rootPayload: p.eap,
|
||||
typeState: st.TypeState,
|
||||
log: log.WithField("type", fmt.Sprintf("%T", np)).WithField("code", t),
|
||||
settings: stm.GetEAPSettings().ProtocolSettings[t],
|
||||
handleInner: func(pp protocol.Payload, sm protocol.StateManager) (protocol.Payload, error) {
|
||||
return p.handleEAP(pp, sm)
|
||||
},
|
||||
var ctx *context
|
||||
if parentContext != nil {
|
||||
ctx = parentContext.Inner(np, t).(*context)
|
||||
} else {
|
||||
ctx = &context{
|
||||
req: p.r,
|
||||
rootPayload: p.eap,
|
||||
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() {
|
||||
ctx.log.Debug("Root-EAP: protocol not offerable, skipping")
|
||||
ctx.Log().Debug("Root-EAP: protocol not offerable, skipping")
|
||||
return next()
|
||||
}
|
||||
ctx.log.Debug("Root-EAP: Passing to protocol")
|
||||
ctx.Log().Debug("Root-EAP: Passing to protocol")
|
||||
|
||||
res := &eap.Payload{
|
||||
Code: protocol.CodeRequest,
|
||||
@ -137,7 +142,7 @@ func (p *Packet) handleEAP(pp protocol.Payload, stm protocol.StateManager) (*eap
|
||||
stm.SetEAPState(p.state, st)
|
||||
|
||||
if ctx.endModifier != nil {
|
||||
p.endModifier = ctx.endModifier
|
||||
p.endModifier = ctx.callEndModifier
|
||||
}
|
||||
|
||||
switch ctx.endStatus {
|
||||
|
@ -25,6 +25,7 @@ type Context interface {
|
||||
IsProtocolStart(p Type) bool
|
||||
|
||||
HandleInnerEAP(Payload, StateManager) (Payload, error)
|
||||
Inner(Payload, Type) Context
|
||||
EndInnerProtocol(Status, func(p *radius.Packet) *radius.Packet)
|
||||
|
||||
Log() *log.Entry
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"layeh.com/radius/rfc2759"
|
||||
"layeh.com/radius/rfc3079"
|
||||
)
|
||||
|
||||
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) {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
||||
"goauthentik.io/internal/outpost/radius/eap/protocol/eap"
|
||||
"goauthentik.io/internal/outpost/radius/eap/protocol/peap"
|
||||
"layeh.com/radius"
|
||||
"layeh.com/radius/vendors/microsoft"
|
||||
)
|
||||
|
||||
const TypeMSCHAPv2 protocol.Type = 26
|
||||
@ -63,7 +65,7 @@ func (p *Payload) Decode(raw []byte) error {
|
||||
|
||||
p.ValueSize = raw[4]
|
||||
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.Name = raw[5+p.ValueSize:]
|
||||
@ -136,7 +138,7 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
|
||||
}
|
||||
return succ
|
||||
} else if p.OpCode == OpSuccess && p.st.Authenticated {
|
||||
return &peap.ExtensionPayload{
|
||||
ep := &peap.ExtensionPayload{
|
||||
AVPs: []peap.ExtensionAVP{
|
||||
{
|
||||
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
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package mschapv2
|
||||
|
||||
type State struct {
|
||||
Challenge []byte
|
||||
PeerChallenge []byte
|
||||
Authenticated bool
|
||||
Challenge []byte
|
||||
PeerChallenge []byte
|
||||
Authenticated bool
|
||||
IsProtocolEnded bool
|
||||
recvKey []byte
|
||||
sendKey []byte
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/radius/eap/debug"
|
||||
"goauthentik.io/internal/outpost/radius/eap/protocol"
|
||||
)
|
||||
|
||||
@ -14,6 +15,7 @@ type ExtensionPayload struct {
|
||||
}
|
||||
|
||||
func (ep *ExtensionPayload) Decode(raw []byte) error {
|
||||
log.WithField("raw", debug.FormatBytes(raw)).Debugf("PEAP-Extension: decode raw")
|
||||
ep.AVPs = []ExtensionAVP{}
|
||||
offset := 0
|
||||
for {
|
||||
@ -32,7 +34,7 @@ func (ep *ExtensionPayload) Decode(raw []byte) error {
|
||||
}
|
||||
|
||||
func (ep *ExtensionPayload) Encode() ([]byte, error) {
|
||||
log.Debug("PEAP: Extension encode")
|
||||
log.Debug("PEAP-Extension: encode")
|
||||
buff := []byte{}
|
||||
for _, avp := range ep.AVPs {
|
||||
buff = append(buff, avp.Encode()...)
|
||||
|
@ -51,7 +51,7 @@ func (p *Payload) Decode(raw []byte) error {
|
||||
func (p *Payload) Encode() ([]byte, error) {
|
||||
log.Debug("PEAP: Encoding inner EAP")
|
||||
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()
|
||||
if err != nil {
|
||||
@ -129,6 +129,7 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
|
||||
res, err := ctx.HandleInnerEAP(ep, p)
|
||||
if err != nil {
|
||||
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)
|
||||
// Extension payloads handle encoding differently
|
||||
|
@ -23,7 +23,7 @@ func (p *Payload) innerHandler(ctx protocol.Context) {
|
||||
ctx.EndInnerProtocol(protocol.StatusError, nil)
|
||||
return
|
||||
}
|
||||
pl := p.Inner.Handle(ctx)
|
||||
pl := p.Inner.Handle(ctx.Inner(p.Inner, p.Inner.Type()))
|
||||
enc, err := pl.Encode()
|
||||
if err != nil {
|
||||
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),
|
||||
)
|
||||
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.MSMPPESendKey_Set(r, p.st.MPPEKey[64:64+32])
|
||||
return r
|
||||
|
Reference in New Issue
Block a user