Skip to content

Commit

Permalink
Fuzzing for HandleNAS (#93)
Browse files Browse the repository at this point in the history
* Initial fuzzing code for HandleNAS

* Add nil check in SendSearchNFInstances

* Fix crash at HandleRegistrationRequest by too short MobileIdentity

* Test case: crash at nasConvert.SuciToString

* Error check for mobile identity

* Fix crash when SUCI is NAI

* Fuzzing at Authentication state

* Fix crash by invalid Authentication Response

* Fix crash by invalid Authentication Failure

* Check empty Mobile Identity

* fix golangci-lint error

* Disable fuzzing in older golang

* Update NAS module to v1.1.1
  • Loading branch information
ShouheiNishi authored May 10, 2023
1 parent 5657aa2 commit 60e861e
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 18 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/antonfisher/nested-logrus-formatter v1.3.1
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/free5gc/aper v1.0.4
github.com/free5gc/nas v1.1.0
github.com/free5gc/nas v1.1.1
github.com/free5gc/ngap v1.0.6
github.com/free5gc/openapi v1.0.6
github.com/free5gc/util v1.0.3
Expand All @@ -18,6 +18,7 @@ require (
github.com/mitchellh/mapstructure v1.4.1
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.8.1
github.com/urfave/cli v1.22.5
gopkg.in/yaml.v2 v2.4.0
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/free5gc/aper v1.0.4 h1:Ufbf5lzbXBOhSdUSaIdAhFMOjggsX4p6eWMrpzrrD60=
github.com/free5gc/aper v1.0.4/go.mod h1:3K/m47BIPR2xhBkuHD1unp2LnArVtt3iTI4De0bCqpI=
github.com/free5gc/nas v1.1.0 h1:8mIncMWG0L9BA+3oMlrYocfZ6qE+P7jZ1oe/tnXLWAs=
github.com/free5gc/nas v1.1.0/go.mod h1:fjWwpyp7/wOyL72HTkjvIe9YTCfGyZosjITsI5sXyuU=
github.com/free5gc/nas v1.1.1 h1:xUsqOOrb3kH38TQCzwZY7WN6WJkIerjERNjORDtnCbo=
github.com/free5gc/nas v1.1.1/go.mod h1:fjWwpyp7/wOyL72HTkjvIe9YTCfGyZosjITsI5sXyuU=
github.com/free5gc/ngap v1.0.6 h1:f9sKqHMNrFZVo9Kp8hAyrCXSoI8l746N5O+DFn7vKHA=
github.com/free5gc/ngap v1.0.6/go.mod h1:TG1kwwU/EyIlJ3bxY591rdxpD5ZeYnLZTzoWjcfvrBM=
github.com/free5gc/openapi v1.0.4/go.mod h1:KRCnnp0GeK0Bl4gnrX79cQAidKXNENf8VRdG0y9R0Fc=
Expand Down
71 changes: 58 additions & 13 deletions internal/gmm/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,17 +458,28 @@ func HandleRegistrationRequest(ue *context.AmfUe, anType models.AccessType, proc
}

mobileIdentity5GSContents := registrationRequest.MobileIdentity5GS.GetMobileIdentity5GSContents()
if len(mobileIdentity5GSContents) < 1 {
return errors.New("broken MobileIdentity5GS")
}
ue.IdentityTypeUsedForRegistration = nasConvert.GetTypeOfIdentity(mobileIdentity5GSContents[0])
switch ue.IdentityTypeUsedForRegistration { // get type of identity
case nasMessage.MobileIdentity5GSTypeNoIdentity:
ue.GmmLog.Debugf("No Identity")
case nasMessage.MobileIdentity5GSTypeSuci:
var plmnId string
ue.Suci, plmnId = nasConvert.SuciToString(mobileIdentity5GSContents)
ue.PlmnId = util.PlmnIdStringToModels(plmnId)
if suci, plmnId, err := nasConvert.SuciToStringWithError(mobileIdentity5GSContents); err != nil {
return fmt.Errorf("decode SUCI failed: %w", err)
} else if plmnId == "" {
return errors.New("empty plmnId")
} else {
ue.Suci = suci
ue.PlmnId = util.PlmnIdStringToModels(plmnId)
}
ue.GmmLog.Debugf("SUCI: %s", ue.Suci)
case nasMessage.MobileIdentity5GSType5gGuti:
guamiFromUeGutiTmp, guti := nasConvert.GutiToString(mobileIdentity5GSContents)
guamiFromUeGutiTmp, guti, err := nasConvert.GutiToStringWithError(mobileIdentity5GSContents)
if err != nil {
return fmt.Errorf("decode GUTI failed: %w", err)
}
guamiFromUeGuti = guamiFromUeGutiTmp
ue.GmmLog.Debugf("GUTI: %s", guti)

Expand All @@ -487,11 +498,17 @@ func HandleRegistrationRequest(ue *context.AmfUe, anType models.AccessType, proc
ue.Guti = guti
}
case nasMessage.MobileIdentity5GSTypeImei:
imei := nasConvert.PeiToString(mobileIdentity5GSContents)
imei, err := nasConvert.PeiToStringWithError(mobileIdentity5GSContents)
if err != nil {
return fmt.Errorf("decode PEI failed: %w", err)
}
ue.Pei = imei
ue.GmmLog.Debugf("PEI: %s", imei)
case nasMessage.MobileIdentity5GSTypeImeisv:
imeisv := nasConvert.PeiToString(mobileIdentity5GSContents)
imeisv, err := nasConvert.PeiToStringWithError(mobileIdentity5GSContents)
if err != nil {
return fmt.Errorf("decode PEI failed: %w", err)
}
ue.Pei = imeisv
ue.GmmLog.Debugf("PEI: %s", imeisv)
}
Expand Down Expand Up @@ -1422,6 +1439,9 @@ func HandleIdentityResponse(ue *context.AmfUe, identityResponse *nasMessage.Iden
ue.GmmLog.Info("Handle Identity Response")

mobileIdentityContents := identityResponse.MobileIdentity.GetMobileIdentityContents()
if len(mobileIdentityContents) < 1 {
return errors.New("empty Mobile Identity")
}
if nasConvert.GetTypeOfIdentity(mobileIdentityContents[0]) != ue.RequestIdentityType {
return fmt.Errorf("Received identity type doesn't match request type")
}
Expand All @@ -1433,15 +1453,23 @@ func HandleIdentityResponse(ue *context.AmfUe, identityResponse *nasMessage.Iden

switch nasConvert.GetTypeOfIdentity(mobileIdentityContents[0]) { // get type of identity
case nasMessage.MobileIdentity5GSTypeSuci:
var plmnId string
ue.Suci, plmnId = nasConvert.SuciToString(mobileIdentityContents)
ue.PlmnId = util.PlmnIdStringToModels(plmnId)
if suci, plmnId, err := nasConvert.SuciToStringWithError(mobileIdentityContents); err != nil {
return fmt.Errorf("decode SUCI failed: %w", err)
} else if plmnId == "" {
return errors.New("empty plmnId")
} else {
ue.Suci = suci
ue.PlmnId = util.PlmnIdStringToModels(plmnId)
}
ue.GmmLog.Debugf("get SUCI: %s", ue.Suci)
case nasMessage.MobileIdentity5GSType5gGuti:
if ue.MacFailed {
return fmt.Errorf("NAS message integrity check failed")
}
_, guti := nasConvert.GutiToString(mobileIdentityContents)
_, guti, err := nasConvert.GutiToStringWithError(mobileIdentityContents)
if err != nil {
return fmt.Errorf("decode GUTI failed: %w", err)
}
ue.Guti = guti
ue.GmmLog.Debugf("get GUTI: %s", guti)
case nasMessage.MobileIdentity5GSType5gSTmsi:
Expand All @@ -1459,14 +1487,20 @@ func HandleIdentityResponse(ue *context.AmfUe, identityResponse *nasMessage.Iden
if ue.MacFailed {
return fmt.Errorf("NAS message integrity check failed")
}
imei := nasConvert.PeiToString(mobileIdentityContents)
imei, err := nasConvert.PeiToStringWithError(mobileIdentityContents)
if err != nil {
return fmt.Errorf("decode PEI failed: %w", err)
}
ue.Pei = imei
ue.GmmLog.Debugf("get PEI: %s", imei)
case nasMessage.MobileIdentity5GSTypeImeisv:
if ue.MacFailed {
return fmt.Errorf("NAS message integrity check failed")
}
imeisv := nasConvert.PeiToString(mobileIdentityContents)
imeisv, err := nasConvert.PeiToStringWithError(mobileIdentityContents)
if err != nil {
return fmt.Errorf("decode PEI failed: %w", err)
}
ue.Pei = imeisv
ue.GmmLog.Debugf("get PEI: %s", imeisv)
}
Expand Down Expand Up @@ -1987,6 +2021,9 @@ func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessTyp
if err := mapstructure.Decode(ue.AuthenticationCtx.Var5gAuthData, &av5gAka); err != nil {
return fmt.Errorf("Var5gAuthData Convert Type Error")
}
if authenticationResponse.AuthenticationResponseParameter == nil {
return fmt.Errorf("AuthenticationResponseParamete is nil")
}
resStar := authenticationResponse.AuthenticationResponseParameter.GetRES()

// Calculate HRES* (TS 33.501 Annex A.5)
Expand Down Expand Up @@ -2152,6 +2189,9 @@ func HandleAuthenticationFailure(ue *context.AmfUe, anType models.AccessType,
fsm.ArgsType{ArgAmfUe: ue, ArgAccessType: anType})
}

if authenticationFailure.AuthenticationFailureParameter == nil {
return errors.New("AuthenticationFailureParameter is nil")
}
auts := authenticationFailure.AuthenticationFailureParameter.GetAuthenticationFailureParameter()
resynchronizationInfo := &models.ResynchronizationInfo{
Auts: hex.EncodeToString(auts[:]),
Expand Down Expand Up @@ -2246,7 +2286,12 @@ func HandleSecurityModeComplete(ue *context.AmfUe, anType models.AccessType, pro

if securityModeComplete.IMEISV != nil {
ue.GmmLog.Debugln("receieve IMEISV")
ue.Pei = nasConvert.PeiToString(securityModeComplete.IMEISV.Octet[:])
if pei, err := nasConvert.PeiToStringWithError(securityModeComplete.IMEISV.Octet[:]); err != nil {
gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "")
return fmt.Errorf("decode PEI failed: %w", err)
} else {
ue.Pei = pei
}
}

// TODO: AMF shall set the NAS COUNTs to zero if horizontal derivation of KAMF is performed
Expand Down
11 changes: 9 additions & 2 deletions internal/gmm/message/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package message
import (
"encoding/base64"
"encoding/hex"
"fmt"

"github.com/mitchellh/mapstructure"

Expand Down Expand Up @@ -500,7 +501,10 @@ func BuildRegistrationAccept(
// TODO: set smsAllowed value of RegistrationResult5GS if need

if ue.Guti != "" {
gutiNas := nasConvert.GutiToNas(ue.Guti)
gutiNas, err := nasConvert.GutiToNasWithError(ue.Guti)
if err != nil {
return nil, fmt.Errorf("encode GUTI failed: %w", err)
}
registrationAccept.GUTI5G = &gutiNas
registrationAccept.GUTI5G.SetIei(nasMessage.RegistrationAcceptGUTI5GType)
}
Expand Down Expand Up @@ -720,7 +724,10 @@ func BuildConfigurationUpdateCommand(ue *context.AmfUe, anType models.AccessType
}

if ue.Guti != "" {
gutiNas := nasConvert.GutiToNas(ue.Guti)
gutiNas, err := nasConvert.GutiToNasWithError(ue.Guti)
if err != nil {
return nil, fmt.Errorf("encode GUTI failed: %w", err)
}
configurationUpdateCommand.GUTI5G = &gutiNas
configurationUpdateCommand.GUTI5G.SetIei(nasMessage.ConfigurationUpdateCommandGUTI5GType)
}
Expand Down
Loading

0 comments on commit 60e861e

Please sign in to comment.