Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer
2025-05-24 18:27:54 +02:00
parent 3027cdcc4b
commit 7b97e92094
7 changed files with 67 additions and 68 deletions

1
go.mod
View File

@ -11,7 +11,6 @@ require (
github.com/go-ldap/ldap/v3 v3.4.11
github.com/go-openapi/runtime v0.28.0
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/gopacket v1.1.19
github.com/google/uuid v1.6.0
github.com/gorilla/handlers v1.5.2
github.com/gorilla/mux v1.8.1

2
go.sum
View File

@ -154,8 +154,6 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=

View File

@ -2,26 +2,8 @@ package debug
import (
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
log "github.com/sirupsen/logrus"
"layeh.com/radius"
)
func DebugPacket(p *radius.Packet) {
log.Debug(p)
log.Debug(p.Attributes)
n, _ := p.Encode()
log.Debug(n)
packet := gopacket.NewPacket(n, layers.LayerTypeRADIUS, gopacket.Default)
layer := packet.Layer(layers.LayerTypeRADIUS)
if layer == nil {
return
}
log.Debug(layer.(*layers.RADIUS))
}
func FormatBytes(d []byte) string {
b := d
if len(b) > 32 {

View File

@ -1,38 +0,0 @@
package mschapv2
import (
"bytes"
"errors"
"layeh.com/radius/rfc2759"
"layeh.com/radius/rfc3079"
)
func (p *Payload) checkChapPassword(res *Response) ([]byte, error) {
byteUser := []byte("foo")
bytePwd := []byte("bar")
ntResponse, err := rfc2759.GenerateNTResponse(p.st.Challenge, p.st.PeerChallenge, byteUser, bytePwd)
if err != nil {
return nil, err
}
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
}
return []byte(authenticatorResponse), nil
}

View File

@ -1,6 +1,7 @@
package mschapv2
import (
"bytes"
"encoding/binary"
"fmt"
@ -115,6 +116,8 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
MSCHAPv2ID: rootEap.ID + 1,
}
settings := ctx.ProtocolSettings().(Settings)
ctx.Log().Debugf("MSCHAPv2: OpCode: %d", p.OpCode)
if p.OpCode == OpResponse {
res, err := ParseResponse(p.Response)
@ -123,21 +126,28 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
return nil
}
p.st.PeerChallenge = res.Challenge
auth, err := p.checkChapPassword(res)
auth, err := settings.AuthenticateRequest(AuthRequest{
Challenge: p.st.Challenge,
PeerChallenge: p.st.PeerChallenge,
})
if err != nil {
ctx.Log().WithError(err).Warning("MSCHAPv2: failed to check password")
return nil
}
if !bytes.Equal(auth.NTResponse, res.NTResponse) {
ctx.Log().Warning("MSCHAPv2: NT response mismatch")
return nil
}
ctx.Log().Info("MSCHAPv2: Successfully checked password")
p.st.Authenticated = true
p.st.AuthResponse = auth
succ := &SuccessRequest{
Payload: &Payload{
OpCode: OpSuccess,
},
Authenticator: auth,
Authenticator: []byte(auth.AuthenticatorResponse),
}
return succ
} else if p.OpCode == OpSuccess && p.st.Authenticated {
} else if p.OpCode == OpSuccess && p.st.AuthResponse != nil {
ep := &peap.ExtensionPayload{
AVPs: []peap.ExtensionAVP{
{
@ -152,10 +162,10 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
} 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)
microsoft.MSMPPERecvKey_Set(r, p.st.AuthResponse.RecvKey)
}
if len(microsoft.MSMPPESendKey_Get(r, ctx.Packet().Packet)) < 1 {
microsoft.MSMPPESendKey_Set(r, p.st.sendKey)
microsoft.MSMPPESendKey_Set(r, p.st.AuthResponse.SendKey)
}
return r
})

View File

@ -0,0 +1,50 @@
package mschapv2
import (
"layeh.com/radius/rfc2759"
"layeh.com/radius/rfc3079"
)
type Settings struct {
AuthenticateRequest func(req AuthRequest) (*AuthResponse, error)
}
type AuthRequest struct {
Challenge []byte
PeerChallenge []byte
}
type AuthResponse struct {
NTResponse []byte
RecvKey []byte
SendKey []byte
AuthenticatorResponse string
}
func DebugStaticCredentials(user, password []byte) func(req AuthRequest) (*AuthResponse, error) {
return func(req AuthRequest) (*AuthResponse, error) {
res := &AuthResponse{}
ntResponse, err := rfc2759.GenerateNTResponse(req.Challenge, req.PeerChallenge, user, password)
if err != nil {
return nil, err
}
res.NTResponse = ntResponse
res.RecvKey, err = rfc3079.MakeKey(ntResponse, password, false)
if err != nil {
return nil, err
}
res.SendKey, err = rfc3079.MakeKey(ntResponse, password, true)
if err != nil {
return nil, err
}
res.AuthenticatorResponse, err = rfc2759.GenerateAuthenticatorResponse(req.Challenge, req.PeerChallenge, ntResponse, user, password)
if err != nil {
return nil, err
}
return res, nil
}
}

View File

@ -3,8 +3,6 @@ package mschapv2
type State struct {
Challenge []byte
PeerChallenge []byte
Authenticated bool
IsProtocolEnded bool
recvKey []byte
sendKey []byte
AuthResponse *AuthResponse
}