From 67f627a9256a65b447bb3c64b4eaf9a32816a15a Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sat, 24 May 2025 14:50:16 +0200 Subject: [PATCH] mostly working Signed-off-by: Jens Langhammer --- internal/outpost/radius/eap/context.go | 29 +++++++++++---- internal/outpost/radius/eap/handler.go | 35 +++++++++++-------- .../outpost/radius/eap/protocol/context.go | 1 + .../radius/eap/protocol/mschapv2/auth.go | 12 +++++++ .../radius/eap/protocol/mschapv2/payload.go | 19 ++++++++-- .../radius/eap/protocol/mschapv2/state.go | 9 +++-- .../radius/eap/protocol/peap/extension.go | 4 ++- .../radius/eap/protocol/peap/payload.go | 3 +- .../outpost/radius/eap/protocol/tls/inner.go | 2 +- .../radius/eap/protocol/tls/payload.go | 1 + 10 files changed, 86 insertions(+), 29 deletions(-) diff --git a/internal/outpost/radius/eap/context.go b/internal/outpost/radius/eap/context.go index 1e3ce0cbfd..fb833523f1 100644 --- a/internal/outpost/radius/eap/context.go +++ b/internal/outpost/radius/eap/context.go @@ -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 +} diff --git a/internal/outpost/radius/eap/handler.go b/internal/outpost/radius/eap/handler.go index 7df01a289e..a395a3a43d 100644 --- a/internal/outpost/radius/eap/handler.go +++ b/internal/outpost/radius/eap/handler.go @@ -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 { diff --git a/internal/outpost/radius/eap/protocol/context.go b/internal/outpost/radius/eap/protocol/context.go index ff019e63b5..2a086d3008 100644 --- a/internal/outpost/radius/eap/protocol/context.go +++ b/internal/outpost/radius/eap/protocol/context.go @@ -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 diff --git a/internal/outpost/radius/eap/protocol/mschapv2/auth.go b/internal/outpost/radius/eap/protocol/mschapv2/auth.go index 2a14bd1743..fc170cfe3f 100644 --- a/internal/outpost/radius/eap/protocol/mschapv2/auth.go +++ b/internal/outpost/radius/eap/protocol/mschapv2/auth.go @@ -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 diff --git a/internal/outpost/radius/eap/protocol/mschapv2/payload.go b/internal/outpost/radius/eap/protocol/mschapv2/payload.go index 9004c2b2b3..7878e69548 100644 --- a/internal/outpost/radius/eap/protocol/mschapv2/payload.go +++ b/internal/outpost/radius/eap/protocol/mschapv2/payload.go @@ -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 } diff --git a/internal/outpost/radius/eap/protocol/mschapv2/state.go b/internal/outpost/radius/eap/protocol/mschapv2/state.go index 7f1f32aaf0..21bdc8cb59 100644 --- a/internal/outpost/radius/eap/protocol/mschapv2/state.go +++ b/internal/outpost/radius/eap/protocol/mschapv2/state.go @@ -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 } diff --git a/internal/outpost/radius/eap/protocol/peap/extension.go b/internal/outpost/radius/eap/protocol/peap/extension.go index 216e6337fa..f499a9883b 100644 --- a/internal/outpost/radius/eap/protocol/peap/extension.go +++ b/internal/outpost/radius/eap/protocol/peap/extension.go @@ -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()...) diff --git a/internal/outpost/radius/eap/protocol/peap/payload.go b/internal/outpost/radius/eap/protocol/peap/payload.go index 6be31f1016..79500f8691 100644 --- a/internal/outpost/radius/eap/protocol/peap/payload.go +++ b/internal/outpost/radius/eap/protocol/peap/payload.go @@ -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 diff --git a/internal/outpost/radius/eap/protocol/tls/inner.go b/internal/outpost/radius/eap/protocol/tls/inner.go index 5bbfbcbe86..4aff0be552 100644 --- a/internal/outpost/radius/eap/protocol/tls/inner.go +++ b/internal/outpost/radius/eap/protocol/tls/inner.go @@ -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") diff --git a/internal/outpost/radius/eap/protocol/tls/payload.go b/internal/outpost/radius/eap/protocol/tls/payload.go index 5db45c377d..fb6d95a2c8 100644 --- a/internal/outpost/radius/eap/protocol/tls/payload.go +++ b/internal/outpost/radius/eap/protocol/tls/payload.go @@ -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