--- title: 'IMPLEMENTATION' disqus: hackmd --- MODIFY THE PACKET WITH "AUTHENTICATION REQUEST" === [TOC] ## Explain 1 1. Explain 1 Modify in free 5GC ![Screenshot 2024-04-09 at 14.55.15](https://hackmd.io/_uploads/HJhAvDMlC.png) Original Code ``` b= func BuildAuthenticationRequest(ue *context.AmfUe) ([]byte, error) { m := nas.NewMessage() m.GmmMessage = nas.NewGmmMessage() m.GmmHeader.SetMessageType(nas.MsgTypeAuthenticationRequest) authenticationRequest := nasMessage.NewAuthenticationRequest(0) authenticationRequest.SetExtendedProtocolDiscriminator(nasMessage.Epd5GSMobilityManagementMessage) authenticationRequest.SpareHalfOctetAndSecurityHeaderType.SetSecurityHeaderType(nas.SecurityHeaderTypePlainNas) authenticationRequest.SpareHalfOctetAndSecurityHeaderType.SetSpareHalfOctet(0) authenticationRequest.AuthenticationRequestMessageIdentity.SetMessageType(nas.MsgTypeAuthenticationRequest) authenticationRequest.SpareHalfOctetAndNgksi = nasConvert.SpareHalfOctetAndNgksiToNas(ue.NgKsi) authenticationRequest.ABBA.SetLen(uint8(len(ue.ABBA))) authenticationRequest.ABBA.SetABBAContents(ue.ABBA) switch ue.AuthenticationCtx.AuthType { case models.AuthType__5_G_AKA: var tmpArray [16]byte var av5gAka models.Av5gAka if err := mapstructure.Decode(ue.AuthenticationCtx.Var5gAuthData, &av5gAka); err != nil { logger.GmmLog.Error("Var5gAuthData Convert Type Error") return nil, err } rand, err := hex.DecodeString(av5gAka.Rand) if err != nil { return nil, err } authenticationRequest.AuthenticationParameterRAND = nasType. NewAuthenticationParameterRAND(nasMessage.AuthenticationRequestAuthenticationParameterRANDType) copy(tmpArray[:], rand[0:16]) authenticationRequest.AuthenticationParameterRAND.SetRANDValue(tmpArray) autn, err := hex.DecodeString(av5gAka.Autn) if err != nil { return nil, err } authenticationRequest.AuthenticationParameterAUTN = nasType. NewAuthenticationParameterAUTN(nasMessage.AuthenticationRequestAuthenticationParameterAUTNType) authenticationRequest.AuthenticationParameterAUTN.SetLen(uint8(len(autn))) copy(tmpArray[:], autn[0:16]) authenticationRequest.AuthenticationParameterAUTN.SetAUTN(tmpArray) case models.AuthType_EAP_AKA_PRIME: eapMsg := ue.AuthenticationCtx.Var5gAuthData.(string) rawEapMsg, err := base64.StdEncoding.DecodeString(eapMsg) if err != nil { return nil, err } authenticationRequest.EAPMessage = nasType.NewEAPMessage(nasMessage.AuthenticationRequestEAPMessageType) authenticationRequest.EAPMessage.SetLen(uint16(len(rawEapMsg))) authenticationRequest.EAPMessage.SetEAPMessage(rawEapMsg) } m.GmmMessage.AuthenticationRequest = authenticationRequest return m.PlainNasEncode() } ``` Modify Code ```b= func BuildAuthenticationRequest(ue *context.AmfUe) ([]byte, error) { m := nas.NewMessage() m.GmmMessage = nas.NewGmmMessage() m.GmmHeader.SetMessageType(nas.MsgTypeAuthenticationRequest) authenticationRequest := nasMessage.NewAuthenticationRequest(0) authenticationRequest.SetExtendedProtocolDiscriminator(nasMessage.Epd5GSMobilityManagementMessage) authenticationRequest.SpareHalfOctetAndSecurityHeaderType.SetSecurityHeaderType(nas.SecurityHeaderTypePlainNas) authenticationRequest.SpareHalfOctetAndSecurityHeaderType.SetSpareHalfOctet(0) authenticationRequest.AuthenticationRequestMessageIdentity.SetMessageType(nas.MsgTypeAuthenticationRequest) authenticationRequest.SpareHalfOctetAndNgksi = nasConvert.SpareHalfOctetAndNgksiToNas(ue.NgKsi) authenticationRequest.ABBA.SetLen(uint8(len(ue.ABBA))) authenticationRequest.ABBA.SetABBAContents(ue.ABBA) authenticationRequest.AuthenticationParameterRAND = nasType.NewAuthenticationParameterRAND(nasMessage.AuthenticationRequestAuthenticationParameterRANDType) //copy(tmpArray[:], "f63d9c08cfc5d42f26f20419de208bde") var av5gAka models.Av5gAka av5gAka.Autn = "e6ab5a8dfdee8000ec9fd483d54cb7d8" var tmpArray string = "568c804753fe5ebd1f6707ec044f2c2c" b, err := hex.DecodeString(tmpArray) if err != nil { panic(err) } var a [16]uint8 copy(a[:], b) authenticationRequest.AuthenticationParameterRAND.SetRANDValue(a) //av5gAka.Rand = strconv.Itoa(uint8(a)) authenticationRequest.AuthenticationParameterAUTN = nasType.NewAuthenticationParameterAUTN(nasMessage.AuthenticationRequestAuthenticationParameterAUTNType) var autn string = "e6ab5a8dfdee8000ec9fd483d54cb7d8" c, err := hex.DecodeString(autn) if err != nil { panic(err) } var d [16]uint8 copy(d[:], c) authenticationRequest.AuthenticationParameterAUTN.SetLen(uint8(len(d))) authenticationRequest.AuthenticationParameterAUTN.SetAUTN(d) fmt.Printf("Authentication Request paramenter - ExtendedProtocolDiscriminator: %s\n", authenticationRequest.ExtendedProtocolDiscriminator) fmt.Printf("Authentication Request paramenter - SpareHalfOctetAndSecurityHeaderType: %s\n", authenticationRequest.SpareHalfOctetAndSecurityHeaderType) fmt.Printf("Authentication Request paramenter - AuthenticationParameterAUTN: %s\n", authenticationRequest.AuthenticationParameterAUTN) fmt.Printf("Authentication Request paramenter - AuthenticationParameterRAND: %s\n", authenticationRequest.AuthenticationParameterRAND) fmt.Printf("Authentication Request paramenter - SpareHalfOctetAndNgksi: %s\n", authenticationRequest.SpareHalfOctetAndNgksi) fmt.Printf("Authentication Request paramenter - SpareHalfOctetAndNgksi: %s\n", authenticationRequest.SpareHalfOctetAndNgksi) fmt.Printf("Authentication Request paramenter - ABBA: %s\n", authenticationRequest.ABBA) fmt.Printf("Authentication Request paramenter - AuthenticationRequestMessageIdentity: %s\n", authenticationRequest.AuthenticationRequestMessageIdentity) //ue.Kseaf = "0fa8ed5965d42132289e6aa1e271642d1e883f8d8ef9775cde0b254b3fc2ea66" //ue.Kamf = "a01d61546ea6bd1d82b46dab5c6887aea945af6f700bece1532e50e4a68df4ad" //ue.DerivateKamf() //switch ue.AuthenticationCtx.AuthType { //case models.AuthType__5_G_AKA: // var tmpArray [16]byte // var av5gAka models.Av5gAka // // if err := mapstructure.Decode(ue.AuthenticationCtx.Var5gAuthData, &av5gAka); err != nil { // logger.GmmLog.Error("Var5gAuthData Convert Type Error") // return nil, err // } // // rand, err := hex.DecodeString(av5gAka.Rand) // if err != nil { // return nil, err // } // authenticationRequest.AuthenticationParameterRAND = // nasType.NewAuthenticationParameterRAND(nasMessage.AuthenticationRequestAuthenticationParameterRANDType) // copy(tmpArray[:], rand[0:16]) // authenticationRequest.AuthenticationParameterRAND.SetRANDValue(tmpArray) // // autn, err := hex.DecodeString(av5gAka.Autn) // if err != nil { // return nil, err // } // authenticationRequest.AuthenticationParameterAUTN = // nasType.NewAuthenticationParameterAUTN(nasMessage.AuthenticationRequestAuthenticationParameterAUTNType) // authenticationRequest.AuthenticationParameterAUTN.SetLen(uint8(len(autn))) // copy(tmpArray[:], autn[0:16]) // authenticationRequest.AuthenticationParameterAUTN.SetAUTN(tmpArray) //case models.AuthType_EAP_AKA_PRIME: // eapMsg := ue.AuthenticationCtx.Var5gAuthData.(string) // rawEapMsg, err := base64.StdEncoding.DecodeString(eapMsg) // if err != nil { // return nil, err // } // authenticationRequest.EAPMessage = nasType.NewEAPMessage(nasMessage.AuthenticationRequestEAPMessageType) // authenticationRequest.EAPMessage.SetLen(uint16(len(rawEapMsg))) // authenticationRequest.EAPMessage.SetEAPMessage(rawEapMsg) //} m.GmmMessage.AuthenticationRequest = authenticationRequest return m.PlainNasEncode() } ``` ## Explain 2 Modify in Free 5GC ![Screenshot 2024-04-09 at 15.18.13](https://hackmd.io/_uploads/Bk66sPGxR.png) Original Code ``` b= // TS 24.501 5.4.1 func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessType, authenticationResponse *nasMessage.AuthenticationResponse, ) error { ue.GmmLog.Info("Handle Authentication Response") ue.StopT3560() if ue.AuthenticationCtx == nil { return fmt.Errorf("Ue Authentication Context is nil") } switch ue.AuthenticationCtx.AuthType { case models.AuthType__5_G_AKA: var av5gAka models.Av5gAka 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) p0, err := hex.DecodeString(av5gAka.Rand) if err != nil { return err } p1 := resStar[:] concat := append(p0, p1...) hResStarBytes := sha256.Sum256(concat) hResStar := hex.EncodeToString(hResStarBytes[16:]) if hResStar != av5gAka.HxresStar { ue.GmmLog.Errorf("HRES* Validation Failure (received: %s, expected: %s)", hResStar, av5gAka.HxresStar) if ue.IdentityTypeUsedForRegistration == nasMessage.MobileIdentity5GSType5gGuti && ue.IdentityRequestSendTimes == 0 { ue.IdentityRequestSendTimes++ gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) return nil } else { gmm_message.SendAuthenticationReject(ue.RanUe[accessType], "") return GmmFSM.SendEvent(ue.State[accessType], AuthFailEvent, fsm.ArgsType{ ArgAmfUe: ue, ArgAccessType: accessType, }, logger.GmmLog) } } response, problemDetails, err := consumer.SendAuth5gAkaConfirmRequest(ue, hex.EncodeToString(resStar[:])) if err != nil { return err } else if problemDetails != nil { ue.GmmLog.Debugf("Auth5gAkaConfirm Error[Problem Detail: %+v]", problemDetails) return nil } switch response.AuthResult { case models.AuthResult_SUCCESS: ue.UnauthenticatedSupi = false ue.Kseaf = response.Kseaf ue.Supi = response.Supi ue.DerivateKamf() ue.GmmLog.Debugln("ue.DerivateKamf()", ue.Kamf) return GmmFSM.SendEvent(ue.State[accessType], AuthSuccessEvent, fsm.ArgsType{ ArgAmfUe: ue, ArgAccessType: accessType, ArgEAPSuccess: false, ArgEAPMessage: "", }, logger.GmmLog) case models.AuthResult_FAILURE: if ue.IdentityTypeUsedForRegistration == nasMessage.MobileIdentity5GSType5gGuti && ue.IdentityRequestSendTimes == 0 { ue.IdentityRequestSendTimes++ gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) return nil } else { gmm_message.SendAuthenticationReject(ue.RanUe[accessType], "") return GmmFSM.SendEvent(ue.State[accessType], AuthFailEvent, fsm.ArgsType{ ArgAmfUe: ue, ArgAccessType: accessType, }, logger.GmmLog) } } case models.AuthType_EAP_AKA_PRIME: response, problemDetails, err := consumer.SendEapAuthConfirmRequest(ue, *authenticationResponse.EAPMessage) if err != nil { return err } else if problemDetails != nil { ue.GmmLog.Debugf("EapAuthConfirm Error[Problem Detail: %+v]", problemDetails) return nil } switch response.AuthResult { case models.AuthResult_SUCCESS: ue.UnauthenticatedSupi = false ue.Kseaf = response.KSeaf ue.Supi = response.Supi ue.DerivateKamf() // TODO: select enc/int algorithm based on ue security capability & amf's policy, // then generate KnasEnc, KnasInt return GmmFSM.SendEvent(ue.State[accessType], AuthSuccessEvent, fsm.ArgsType{ ArgAmfUe: ue, ArgAccessType: accessType, ArgEAPSuccess: true, ArgEAPMessage: response.EapPayload, }, logger.GmmLog) case models.AuthResult_FAILURE: if ue.IdentityTypeUsedForRegistration == nasMessage.MobileIdentity5GSType5gGuti && ue.IdentityRequestSendTimes == 0 { ue.IdentityRequestSendTimes++ gmm_message.SendAuthenticationResult(ue.RanUe[accessType], false, response.EapPayload) gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) return nil } else { gmm_message.SendAuthenticationReject(ue.RanUe[accessType], response.EapPayload) return GmmFSM.SendEvent(ue.State[accessType], AuthFailEvent, fsm.ArgsType{ ArgAmfUe: ue, ArgAccessType: accessType, }, logger.GmmLog) } case models.AuthResult_ONGOING: ue.AuthenticationCtx.Var5gAuthData = response.EapPayload if _, exists := response.Links["eap-session"]; exists { ue.AuthenticationCtx.Links = response.Links } gmm_message.SendAuthenticationRequest(ue.RanUe[accessType]) } } return nil } ``` Modify Code ```b= // TS 24.501 5.4.1 func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessType, authenticationResponse *nasMessage.AuthenticationResponse, ) error { ue.GmmLog.Info("Handle Authentication Response") if ue.T3560 != nil { ue.T3560.Stop() ue.T3560 = nil // clear the timer } // ue.StopT3560() // // if ue.AuthenticationCtx == nil { // return fmt.Errorf("Ue Authentication Context is nil") // } // // switch ue.AuthenticationCtx.AuthType { // case models.AuthType__5_G_AKA: // var av5gAka models.Av5gAka // 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) // p0, err := hex.DecodeString(av5gAka.Rand) // if err != nil { // return err // } // p1 := resStar[:] // concat := append(p0, p1...) // hResStarBytes := sha256.Sum256(concat) // hResStar := hex.EncodeToString(hResStarBytes[16:]) // // if hResStar != av5gAka.HxresStar { // ue.GmmLog.Errorf("HRES* Validation Failure (received: %s, expected: %s)", hResStar, av5gAka.HxresStar) // // if ue.IdentityTypeUsedForRegistration == nasMessage.MobileIdentity5GSType5gGuti && ue.IdentityRequestSendTimes == 0 { // ue.IdentityRequestSendTimes++ // gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) // return nil // } else { // gmm_message.SendAuthenticationReject(ue.RanUe[accessType], "") // return GmmFSM.SendEvent(ue.State[accessType], AuthFailEvent, fsm.ArgsType{ // ArgAmfUe: ue, // ArgAccessType: accessType, // }, logger.GmmLog) // } // } // // response, problemDetails, err := consumer.SendAuth5gAkaConfirmRequest(ue, hex.EncodeToString(resStar[:])) // if err != nil { // return err // } else if problemDetails != nil { // ue.GmmLog.Debugf("Auth5gAkaConfirm Error[Problem Detail: %+v]", problemDetails) // return nil // } // switch response.AuthResult { // case models.AuthResult_SUCCESS: // ue.UnauthenticatedSupi = false // ue.Kseaf = response.Kseaf // ue.Supi = response.Supi // ue.DerivateKamf() // ue.GmmLog.Debugln("ue.DerivateKamf()", ue.Kamf) // return GmmFSM.SendEvent(ue.State[accessType], AuthSuccessEvent, fsm.ArgsType{ // ArgAmfUe: ue, // ArgAccessType: accessType, // ArgEAPSuccess: false, // ArgEAPMessage: "", // }, logger.GmmLog) // case models.AuthResult_FAILURE: // if ue.IdentityTypeUsedForRegistration == nasMessage.MobileIdentity5GSType5gGuti && ue.IdentityRequestSendTimes == 0 { // ue.IdentityRequestSendTimes++ // gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) // return nil // } else { // gmm_message.SendAuthenticationReject(ue.RanUe[accessType], "") // return GmmFSM.SendEvent(ue.State[accessType], AuthFailEvent, fsm.ArgsType{ // ArgAmfUe: ue, // ArgAccessType: accessType, // }, logger.GmmLog) // } // } // case models.AuthType_EAP_AKA_PRIME: // response, problemDetails, err := consumer.SendEapAuthConfirmRequest(ue, *authenticationResponse.EAPMessage) // if err != nil { // return err // } else if problemDetails != nil { // ue.GmmLog.Debugf("EapAuthConfirm Error[Problem Detail: %+v]", problemDetails) // return nil // } // // switch response.AuthResult { // case models.AuthResult_SUCCESS: // ue.UnauthenticatedSupi = false // ue.Kseaf = response.KSeaf // ue.Supi = response.Supi // ue.DerivateKamf() // // TODO: select enc/int algorithm based on ue security capability & amf's policy, // // then generate KnasEnc, KnasInt // return GmmFSM.SendEvent(ue.State[accessType], AuthSuccessEvent, fsm.ArgsType{ // ArgAmfUe: ue, // ArgAccessType: accessType, // ArgEAPSuccess: true, // ArgEAPMessage: response.EapPayload, // }, logger.GmmLog) // case models.AuthResult_FAILURE: // if ue.IdentityTypeUsedForRegistration == nasMessage.MobileIdentity5GSType5gGuti && ue.IdentityRequestSendTimes == 0 { // ue.IdentityRequestSendTimes++ // gmm_message.SendAuthenticationResult(ue.RanUe[accessType], false, response.EapPayload) // gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) // return nil // } else { // gmm_message.SendAuthenticationReject(ue.RanUe[accessType], response.EapPayload) // return GmmFSM.SendEvent(ue.State[accessType], AuthFailEvent, fsm.ArgsType{ // ArgAmfUe: ue, // ArgAccessType: accessType, // }, logger.GmmLog) // } // case models.AuthResult_ONGOING: // ue.AuthenticationCtx.Var5gAuthData = response.EapPayload // if _, exists := response.Links["eap-session"]; exists { // ue.AuthenticationCtx.Links = response.Links // } // gmm_message.SendAuthenticationRequest(ue.RanUe[accessType]) // } // } ue.UnauthenticatedSupi = false ue.Kseaf = "ae43b27609029323b992bd71a7e8351b87b655ae2b13330117cd3e4870bcd79c" ue.Kamf = "4770a89cf767fa0270325dd799ed2ca187c8960b905e38f9bdae02025c64ec5d" ue.Supi = "imsi-208930000000003" ue.DerivateKamf() ue.GmmLog.Debugln("ue.DerivateKamf()", ue.Kamf) return GmmFSM.SendEvent(ue.State[accessType], AuthSuccessEvent, fsm.ArgsType{ ArgAmfUe: ue, ArgAccessType: accessType, ArgEAPSuccess: false, ArgEAPMessage: "", }, logger.GmmLog) return nil } ``` ## Explain 3 # in here we can REMOVE "AUSF" and Fix Parameters Modify in ![Screenshot 2024-04-09 at 15.18.13](https://hackmd.io/_uploads/ryyvaDfx0.png) Original Code ```b= func AuthenticationProcedure(ue *context.AmfUe, accessType models.AccessType) (bool, error) { ue.GmmLog.Info("Authentication procedure") // Check whether UE has SUCI and SUPI if IdentityVerification(ue) { ue.GmmLog.Debugln("UE has SUCI / SUPI") if ue.SecurityContextIsValid() { ue.GmmLog.Debugln("UE has a valid security context - skip the authentication procedure") return true, nil } } else { // Request UE's SUCI by sending identity request ue.IdentityRequestSendTimes++ gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) return false, nil } amfSelf := context.GetSelf() // TODO: consider ausf group id, Routing ID part of SUCI param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{} resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_AUSF, models.NfType_AMF, &param) if err != nil { ue.GmmLog.Error("AMF can not select an AUSF by NRF") gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") return false, err } // select the first AUSF, TODO: select base on other info var ausfUri string for _, nfProfile := range resp.NfInstances { ue.AusfId = nfProfile.NfInstanceId ausfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NAUSF_AUTH, models.NfServiceStatus_REGISTERED) if ausfUri != "" { break } } if ausfUri == "" { err = fmt.Errorf("AMF can not select an AUSF by NRF") ue.GmmLog.Errorf(err.Error()) gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") return false, err } ue.AusfUri = ausfUri response, problemDetails, err := consumer.SendUEAuthenticationAuthenticateRequest(ue, nil) if err != nil { ue.GmmLog.Errorf("Nausf_UEAU Authenticate Request Error: %+v", err) gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") err = fmt.Errorf("Authentication procedure failed") ue.GmmLog.Errorf(err.Error()) return false, err } else if problemDetails != nil { ue.GmmLog.Warnf("Nausf_UEAU Authenticate Request Failed: %+v", problemDetails) var cause uint8 switch problemDetails.Status { case http.StatusForbidden, http.StatusNotFound: cause = nasMessage.Cause5GMMIllegalUE default: cause = nasMessage.Cause5GMMCongestion } gmm_message.SendRegistrationReject(ue.RanUe[accessType], cause, "") err = fmt.Errorf("Authentication procedure failed") ue.GmmLog.Warnf(err.Error()) return false, err } ue.AuthenticationCtx = response ue.ABBA = []uint8{0x00, 0x00} // set ABBA value as described at TS 33.501 Annex A.7.1 gmm_message.SendAuthenticationRequest(ue.RanUe[accessType]) return false, nil } ``` Modify Code ```b= package gmm import ( "bytes" // "crypto/sha256" "encoding/hex" "fmt" // "net/http" func HandleConfigurationUpdateComplete(ue *context.AmfUe, configurationUpdateComplete *nasMessage.ConfigurationUpdateComplete, ) error { ue.GmmLog.Info("Handle Configuration Update Complete") if ue.MacFailed { return fmt.Errorf("NAS message integrity check failed") } // TODO: Stop timer T3555 in TS 24.501 Figure 5.4.4.1.1 in handler // TODO: Send acknowledgment by Nudm_SMD_Info_Service to UDM in handler // import "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" client.Info return nil } func AuthenticationProcedure(ue *context.AmfUe, accessType models.AccessType) (bool, error) { ue.GmmLog.Info("Authentication procedure") // Check whether UE has SUCI and SUPI if IdentityVerification(ue) { ue.GmmLog.Debugln("UE has SUCI / SUPI") if ue.SecurityContextIsValid() { ue.GmmLog.Debugln("UE has a valid security context - skip the authentication procedure") return true, nil } } else { // Request UE's SUCI by sending identity request ue.IdentityRequestSendTimes++ gmm_message.SendIdentityRequest(ue.RanUe[accessType], accessType, nasMessage.MobileIdentity5GSTypeSuci) return false, nil } // amfSelf := context.GetSelf() // // // TODO: consider ausf group id, Routing ID part of SUCI // param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{} // resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_AUSF, models.NfType_AMF, &param) // if err != nil { // ue.GmmLog.Error("AMF can not select an AUSF by NRF") // ue.GmmLog.Error("1111111111") // gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") // return false, err // } // // // select the first AUSF, TODO: select base on other info // var ausfUri string // for _, nfProfile := range resp.NfInstances { // ue.AusfId = nfProfile.NfInstanceId // ausfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NAUSF_AUTH, models.NfServiceStatus_REGISTERED) // if ausfUri != "" { // break // } // } // if ausfUri == "" { // err = fmt.Errorf("AMF can not select an AUSF by NRF") // err = fmt.Errorf("22222222") // ue.GmmLog.Errorf(err.Error()) // //gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") // return false, err // } // ue.AusfUri = ausfUri // // response, problemDetails, err := consumer.SendUEAuthenticationAuthenticateRequest(ue, nil) // if err != nil { // ue.GmmLog.Errorf("Nausf_UEAU Authenticate Request Error: %+v", err) // gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") // err = fmt.Errorf("Authentication procedure failed") // ue.GmmLog.Errorf(err.Error()) // return false, err // } else if problemDetails != nil { // ue.GmmLog.Warnf("Nausf_UEAU Authenticate Request Failed: %+v", problemDetails) // var cause uint8 // switch problemDetails.Status { // case http.StatusForbidden, http.StatusNotFound: // cause = nasMessage.Cause5GMMIllegalUE // default: // cause = nasMessage.Cause5GMMCongestion // } // gmm_message.SendRegistrationReject(ue.RanUe[accessType], cause, "") // err = fmt.Errorf("Authentication procedure failed") // ue.GmmLog.Warnf(err.Error()) // return false, err // } // ue.AuthenticationCtx = response ue.ABBA = []uint8{0x00, 0x00} // set ABBA value as described at TS 33.501 Annex A.7.1 gmm_message.SendAuthenticationRequest(ue.RanUe[accessType]) return false, nil } ``` Modify again in ![image](https://hackmd.io/_uploads/rkal0wzxR.png) Original Code ```b= func SendAuthenticationRequest(ue *context.RanUe) { if ue == nil { logger.GmmLog.Error("SendAuthenticationRequest: RanUe is nil") return } if ue.AmfUe == nil { logger.GmmLog.Error("SendAuthenticationRequest: AmfUe is nil") return } amfUe := ue.AmfUe amfUe.GmmLog.Infof("Send Authentication Request") if amfUe.AuthenticationCtx == nil { amfUe.GmmLog.Error("Authentication Context of UE is nil") return } nasMsg, err := BuildAuthenticationRequest(amfUe) if err != nil { amfUe.GmmLog.Error(err.Error()) return } ngap_message.SendDownlinkNasTransport(ue, nasMsg, nil) if context.GetSelf().T3560Cfg.Enable { cfg := context.GetSelf().T3560Cfg amfUe.GmmLog.Infof("Start T3560 timer") amfUe.T3560 = context.NewTimer(cfg.ExpireTime, cfg.MaxRetryTimes, func(expireTimes int32) { amfUe.GmmLog.Warnf("T3560 expires, retransmit Authentication Request (retry: %d)", expireTimes) ngap_message.SendDownlinkNasTransport(ue, nasMsg, nil) }, func() { amfUe.Lock.Lock() defer amfUe.Lock.Unlock() amfUe.GmmLog.Warnf("T3560 Expires %d times, abort authentication procedure & ongoing 5GMM procedure", cfg.MaxRetryTimes) amfUe.T3560 = nil gmm_common.RemoveAmfUe(amfUe, false) }) } } ``` Modify Code ```b= func SendAuthenticationRequest(ue *context.RanUe) { if ue == nil { logger.GmmLog.Error("SendAuthenticationRequest: RanUe is nil") return } if ue.AmfUe == nil { logger.GmmLog.Error("SendAuthenticationRequest: AmfUe is nil") return } amfUe := ue.AmfUe amfUe.GmmLog.Infof("Send Authentication Request") // if amfUe.AuthenticationCtx == nil { // amfUe.GmmLog.Error("Authentication Context of UE is nil") // return // } nasMsg, err := BuildAuthenticationRequest(amfUe) if err != nil { amfUe.GmmLog.Error(err.Error()) return } ngap_message.SendDownlinkNasTransport(ue, nasMsg, nil) if context.GetSelf().T3560Cfg.Enable { cfg := context.GetSelf().T3560Cfg amfUe.GmmLog.Infof("Start T3560 timer") amfUe.T3560 = context.NewTimer(cfg.ExpireTime, cfg.MaxRetryTimes, func(expireTimes int32) { amfUe.GmmLog.Warnf("T3560 expires, retransmit Authentication Request (retry: %d)", expireTimes) ngap_message.SendDownlinkNasTransport(ue, nasMsg, nil) }, func() { amfUe.Lock.Lock() defer amfUe.Lock.Unlock() amfUe.GmmLog.Warnf("T3560 Expires %d times, abort authentication procedure & ongoing 5GMM procedure", cfg.MaxRetryTimes) amfUe.T3560 = nil gmm_common.RemoveAmfUe(amfUe, false) }) } } ``` we can call from free 5GC ![image](https://hackmd.io/_uploads/HJ2n0vfxC.png) Original Code ```b= func CreatePDUSession(ulNasTransport *nasMessage.ULNASTransport, ue *context.AmfUe, anType models.AccessType, pduSessionID int32, smMessage []uint8, ) (setNewSmContext bool, err error) { var ( snssai models.Snssai dnn string ) // A) AMF shall select an SMF // If the S-NSSAI IE is not included and the user's subscription context obtained from UDM. AMF shall // select a default snssai if ulNasTransport.SNSSAI != nil { snssai = nasConvert.SnssaiToModels(ulNasTransport.SNSSAI) } else { if allowedNssai, ok := ue.AllowedNssai[anType]; ok { snssai = *allowedNssai[0].AllowedSnssai } else { return false, errors.New("Ue doesn't have allowedNssai") } } if ulNasTransport.DNN != nil { dnn = ulNasTransport.DNN.GetDNN() } else { // if user's subscription context obtained from UDM does not contain the default DNN for the, // S-NSSAI, the AMF shall use a locally configured DNN as the DNN dnn = ue.ServingAMF().SupportDnnLists[0] if ue.SmfSelectionData != nil { snssaiStr := util.SnssaiModelsToHex(snssai) if snssaiInfo, ok := ue.SmfSelectionData.SubscribedSnssaiInfos[snssaiStr]; ok { for _, dnnInfo := range snssaiInfo.DnnInfos { if dnnInfo.DefaultDnnIndicator { dnn = dnnInfo.Dnn } } } } } if newSmContext, cause, err := consumer.SelectSmf(ue, anType, pduSessionID, snssai, dnn); err != nil { ue.GmmLog.Errorf("Select SMF failed: %+v", err) ue.GmmLog.Errorf("%+v", err) gmm_message.SendDLNASTransport(ue.RanUe[anType], nasMessage.PayloadContainerTypeN1SMInfo, smMessage, pduSessionID, cause, nil, 0) } else { _, smContextRef, errResponse, problemDetail, err := consumer.SendCreateSmContextRequest( ue, newSmContext, nil, smMessage) if err != nil { ue.GmmLog.Errorf("CreateSmContextRequest Error: %+v", err) return false, nil } else if problemDetail != nil { // TODO: error handling return false, fmt.Errorf("Failed to Create smContext[pduSessionID: %d], Error[%v]", pduSessionID, problemDetail) } else if errResponse != nil { ue.GmmLog.Warnf("PDU Session Establishment Request is rejected by SMF[pduSessionId:%d]", pduSessionID) gmm_message.SendDLNASTransport(ue.RanUe[anType], nasMessage.PayloadContainerTypeN1SMInfo, errResponse.BinaryDataN1SmMessage, pduSessionID, 0, nil, 0) } else { newSmContext.SetSmContextRef(smContextRef) newSmContext.SetUserLocation(deepcopy.Copy(ue.Location).(models.UserLocation)) ue.StoreSmContext(pduSessionID, newSmContext) ue.GmmLog.Infof("create smContext[pduSessionID: %d] Success", pduSessionID) // TODO: handle response(response N2SmInfo to RAN if exists) return true, nil } } return false, nil } ``` Modify again in ![image](https://hackmd.io/_uploads/BJar1dMx0.png) Original Code ```b= func SelectSmf( ue *amf_context.AmfUe, anType models.AccessType, pduSessionID int32, snssai models.Snssai, dnn string, ) (*amf_context.SmContext, uint8, error) { var ( smfID string smfUri string ) ue.GmmLog.Infof("Select SMF [snssai: %+v, dnn: %+v]", snssai, dnn) nrfUri := ue.ServingAMF().NrfUri // default NRF URI is pre-configured by AMF nsiInformation := ue.GetNsiInformationFromSnssai(anType, snssai) if nsiInformation == nil { if ue.NssfUri == "" { // TODO: Set a timeout of NSSF Selection or will starvation here for { if err := SearchNssfNSSelectionInstance(ue, nrfUri, models.NfType_NSSF, models.NfType_AMF, nil); err != nil { ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err) time.Sleep(2 * time.Second) } else { break } } } response, problemDetails, err := NSSelectionGetForPduSession(ue, snssai) if err != nil { err = fmt.Errorf("NSSelection Get Error[%+v]", err) return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err } else if problemDetails != nil { err = fmt.Errorf("NSSelection Get Failed Problem[%+v]", problemDetails) return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err } nsiInformation = response.NsiInformation } smContext := amf_context.NewSmContext(pduSessionID) smContext.SetSnssai(snssai) smContext.SetDnn(dnn) smContext.SetAccessType(anType) if nsiInformation == nil { ue.GmmLog.Warnf("nsiInformation is still nil, use default NRF[%s]", nrfUri) } else { smContext.SetNsInstance(nsiInformation.NsiId) nrfApiUri, err := url.Parse(nsiInformation.NrfId) if err != nil { ue.GmmLog.Errorf("Parse NRF URI error, use default NRF[%s]", nrfUri) } else { nrfUri = fmt.Sprintf("%s://%s", nrfApiUri.Scheme, nrfApiUri.Host) } } param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NSMF_PDUSESSION}), Dnn: optional.NewString(dnn), Snssais: optional.NewInterface(openapi.MarshToJsonString([]models.Snssai{snssai})), } if ue.PlmnId.Mcc != "" { param.TargetPlmnList = optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)) } if amf_context.GetSelf().Locality != "" { param.PreferredLocality = optional.NewString(amf_context.GetSelf().Locality) } ue.GmmLog.Debugf("Search SMF from NRF[%s]", nrfUri) result, err := SendSearchNFInstances(nrfUri, models.NfType_SMF, models.NfType_AMF, &param) if err != nil { return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err } if len(result.NfInstances) == 0 { err = fmt.Errorf("DNN[%s] is not supported or not subscribed in the slice[Snssai: %+v]", dnn, snssai) return nil, nasMessage.Cause5GMMDNNNotSupportedOrNotSubscribedInTheSlice, err } // select the first SMF, TODO: select base on other info for _, nfProfile := range result.NfInstances { smfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NSMF_PDUSESSION, models.NfServiceStatus_REGISTERED) if smfUri != "" { break } } smContext.SetSmfID(smfID) smContext.SetSmfUri(smfUri) return smContext, 0, nil } ``` Modify Code ```b= func SelectSmf( ue *amf_context.AmfUe, anType models.AccessType, pduSessionID int32, snssai models.Snssai, dnn string, ) (*amf_context.SmContext, uint8, error) { var ( smfID string smfUri string ) ue.GmmLog.Infof("Select SMF [snssai: %+v, dnn: %+v]", snssai, dnn) nrfUri := ue.ServingAMF().NrfUri // default NRF URI is pre-configured by AMF ue.GmmLog.Errorf("/////////////////TEST01////////////////") nsiInformation := ue.GetNsiInformationFromSnssai(anType, snssai) ue.GmmLog.Errorf("/////////////////TEST02////////////////") // if nsiInformation == nil { // if ue.NssfUri == "" { // // TODO: Set a timeout of NSSF Selection or will starvation here // for { // // ue.GmmLog.Errorf("/////////////////TEST03////////////////") // // if err := SearchNssfNSSelectionInstance(ue, nrfUri, models.NfType_NSSF, // models.NfType_AMF, nil); err != nil { // // ue.GmmLog.Errorf("/////////////////TEST04////////////////") // // //ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err) // //time.Sleep(2 * time.Second) // // break // // } else { // break // } // } // } // // response, problemDetails, err := NSSelectionGetForPduSession(ue, snssai) // if err != nil { // //err = fmt.Errorf("NSSelection Get Error[%+v]", err) // err_1 = nil // ue.GmmLog.Errorf("////return01////") // return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err_1 // } else if problemDetails != nil { // err = fmt.Errorf("NSSelection Get Failed Problem[%+v]", problemDetails) // ue.GmmLog.Errorf("////return02////") // return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err // } // nsiInformation = response.NsiInformation // } smContext := amf_context.NewSmContext(pduSessionID) smContext.SetSnssai(snssai) smContext.SetDnn(dnn) smContext.SetAccessType(anType) if nsiInformation == nil { ue.GmmLog.Warnf("nsiInformation is still nil, use default NRF[%s]", nrfUri) } else { smContext.SetNsInstance(nsiInformation.NsiId) nrfApiUri, err := url.Parse(nsiInformation.NrfId) if err != nil { ue.GmmLog.Errorf("Parse NRF URI error, use default NRF[%s]", nrfUri) } else { nrfUri = fmt.Sprintf("%s://%s", nrfApiUri.Scheme, nrfApiUri.Host) } } param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NSMF_PDUSESSION}), Dnn: optional.NewString(dnn), Snssais: optional.NewInterface(openapi.MarshToJsonString([]models.Snssai{snssai})), } if ue.PlmnId.Mcc != "" { param.TargetPlmnList = optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)) } if amf_context.GetSelf().Locality != "" { param.PreferredLocality = optional.NewString(amf_context.GetSelf().Locality) } ue.GmmLog.Debugf("Search SMF from NRF[%s]", nrfUri) result, err := SendSearchNFInstances(nrfUri, models.NfType_SMF, models.NfType_AMF, &param) if err != nil { ue.GmmLog.Errorf("////return03////") return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err } if len(result.NfInstances) == 0 { err = fmt.Errorf("DNN[%s] is not supported or not subscribed in the slice[Snssai: %+v]", dnn, snssai) ue.GmmLog.Errorf("////return04////") return nil, nasMessage.Cause5GMMDNNNotSupportedOrNotSubscribedInTheSlice, err } // select the first SMF, TODO: select base on other info for _, nfProfile := range result.NfInstances { smfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NSMF_PDUSESSION, models.NfServiceStatus_REGISTERED) if smfUri != "" { break } } smContext.SetSmfID(smfID) smContext.SetSmfUri(smfUri) ue.GmmLog.Errorf("////return05////") return smContext, 0, nil } ``` This Function Called in SelectSMF ![image](https://hackmd.io/_uploads/r1o5e_MxR.png) Original Code ```b= func NSSelectionGetForPduSession(ue *amf_context.AmfUe, snssai models.Snssai) ( *models.AuthorizedNetworkSliceInfo, *models.ProblemDetails, error, ) { configuration := Nnssf_NSSelection.NewConfiguration() configuration.SetBasePath(ue.NssfUri) client := Nnssf_NSSelection.NewAPIClient(configuration) amfSelf := amf_context.GetSelf() sliceInfoForPduSession := models.SliceInfoForPduSession{ SNssai: &snssai, RoamingIndication: models.RoamingIndication_NON_ROAMING, // not support roaming } e, err := json.Marshal(sliceInfoForPduSession) if err != nil { logger.ConsumerLog.Warnf("json marshal failed: %+v", err) } paramOpt := Nnssf_NSSelection.NSSelectionGetParamOpts{ SliceInfoRequestForPduSession: optional.NewInterface(string(e)), } res, httpResp, localErr := client.NetworkSliceInformationDocumentApi.NSSelectionGet(context.Background(), models.NfType_AMF, amfSelf.NfId, &paramOpt) defer func() { if httpResp != nil { if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { logger.ConsumerLog.Errorf("NSSelectionGet response body cannot close: %+v", rspCloseErr) } } }() if localErr == nil { return &res, nil, nil } else if httpResp != nil { if httpResp.Status != localErr.Error() { return nil, nil, localErr } problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) return nil, &problem, nil } else { return nil, nil, openapi.ReportError("NSSF No Response") } } ``` Modify in ![image](https://hackmd.io/_uploads/ryQI-OGxA.png) Modify Code ```b= func SendSearchNFInstances(nrfUri string, targetNfType, requestNfType models.NfType, param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, ) (models.SearchResult, error) { // Set client and set url fmt.Println("////TEST A////") configuration := Nnrf_NFDiscovery.NewConfiguration() fmt.Println("////TEST B////") configuration.SetBasePath(nrfUri) client := Nnrf_NFDiscovery.NewAPIClient(configuration) fmt.Println("////TEST C////") result, res, err := client.NFInstancesStoreApi.SearchNFInstances(context.TODO(), targetNfType, requestNfType, param) // Handle NFDiscoveryRequest 200 GET,return。 fmt.Println("////TEST D////") if res != nil && res.StatusCode == http.StatusTemporaryRedirect { err = fmt.Errorf("Temporary Redirect For Non NRF Consumer") } if res == nil || res.Body == nil { return result, err } defer func() { if res != nil { if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) } } }() return result, err } ``` This the Result after we have modify ## Remove "AUSF" In Free 5GC ![image](https://hackmd.io/_uploads/ryQYEuGxC.png) ![image](https://hackmd.io/_uploads/Skt0VdzlR.png) ![image](https://hackmd.io/_uploads/BkPgrdGxA.png) ![image](https://hackmd.io/_uploads/ry-zH_fxR.png) In UERANSIM ![image](https://hackmd.io/_uploads/B1ok8ufgC.png) ![image](https://hackmd.io/_uploads/SJS-LOMlA.png) In UERANSIM I have ERROR in "NAS" ![image](https://hackmd.io/_uploads/HkfPLdzgR.png) ## Remove "NSSF" In Free 5G ![image](https://hackmd.io/_uploads/H1pwvOMgC.png) ![image](https://hackmd.io/_uploads/B1bLPdfgR.png) ![image](https://hackmd.io/_uploads/HkntvdGeR.png) ![image](https://hackmd.io/_uploads/H1WjDdzgA.png) ![image](https://hackmd.io/_uploads/HJUhDOMxC.png) GNB ![image](https://hackmd.io/_uploads/r1axPuGeA.png) UERANSIM ![image](https://hackmd.io/_uploads/BkAX__fxC.png) ![image](https://hackmd.io/_uploads/H1zLudMx0.png)