【5G核心网】free5GC UE安全鉴权流程源码分析

    本文分析 Free5gc UE 安全鉴权流程

5G AKA Authentication Procedure

1. AMF 向 AUSF 发起 Nausf_UE_Authentication 请求

    Authentication

       -->  AuthenticationProcedure

                -->  SendUEAuthenticationAuthenticateRequest

func SendUEAuthenticationAuthenticateRequest(ue *amf_context.AmfUe,
	resynchronizationInfo *models.ResynchronizationInfo) (*models.UeAuthenticationCtx, *models.ProblemDetails, error) {
	configuration := Nausf_UEAuthentication.NewConfiguration()
	configuration.SetBasePath(ue.AusfUri)

	client := Nausf_UEAuthentication.NewAPIClient(configuration)

	amfSelf := amf_context.AMF_Self()
	servedGuami := amfSelf.ServedGuamiList[0]

	var authInfo models.AuthenticationInfo
	authInfo.SupiOrSuci = ue.Suci
	if mnc, err := strconv.Atoi(servedGuami.PlmnId.Mnc); err != nil {
		return nil, nil, err
	} else {
		authInfo.ServingNetworkName = fmt.Sprintf("5G:mnc%03d.mcc%s.3gppnetwork.org", mnc, servedGuami.PlmnId.Mcc)
	}
	if resynchronizationInfo != nil {
		authInfo.ResynchronizationInfo = resynchronizationInfo
	}

	ueAuthenticationCtx, httpResponse, err := client.DefaultApi.UeAuthenticationsPost(context.Background(), authInfo)
	if err == nil {
		return &ueAuthenticationCtx, nil, nil
	} else if httpResponse != nil {
		if httpResponse.Status != err.Error() {
			return nil, nil, err
		}
		problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails)
		return nil, &problem, nil
	} else {
		return nil, nil, openapi.ReportError("server no response")
	}
}

    AMF 收到注册请求,如果 AMF 不存在 UE 安全上下文,则发起验证流程,AMF 向 AUSF 发起 Nausf_UEAuthentications 流程,包括 SUCI/SUPI 或者服务网络名

    Resource URI: {apiRoot}/nausf-auth/v1/ue-authentications

Table 6.1.6.2.2-1: Definition of type AuthenticationInfo
Nausf_UE_Authentication

 

 

2. AUSF 处理 Authentication 请求

    HTTPUeAuthenticationsPost

      -->  HandleUeAuthPostRequest

               -->  UeAuthPostRequestProcedure

func UeAuthPostRequestProcedure(updateAuthenticationInfo models.AuthenticationInfo) (*models.UeAuthenticationCtx,
	string, *models.ProblemDetails) {
	var responseBody models.UeAuthenticationCtx
	var authInfoReq models.AuthenticationInfoRequest

	supiOrSuci := updateAuthenticationInfo.SupiOrSuci

	snName := updateAuthenticationInfo.ServingNetworkName

   2.1 根据服务网络名,AUSF 决定是否 AMF 有权发送此消息

    如果服务网络未被授权,则 AUSF 应使用 SERVING_NETWORK_NOT_AUTHORIZED “原因”。 但是这里比较简单,只是正则表达式匹配 5G:mnc[0-9]{3}[.]mcc[0-9]{3}[.]3gppnetwork[.]org

snName := updateAuthenticationInfo.ServingNetworkName
servingNetworkAuthorized := ausf_context.IsServingNetworkAuthorized(snName)
if !servingNetworkAuthorized {
	var problemDetails models.ProblemDetails
	problemDetails.Cause = "SERVING_NETWORK_NOT_AUTHORIZED"
	problemDetails.Status = http.StatusForbidden
	logger.UeAuthPostLog.Infoln("403 forbidden: serving network NOT AUTHORIZED")
	return nil, "", &problemDetails
}
logger.UeAuthPostLog.Infoln("Serving network authorized")

   2.2 如果请求 body 包含 ResynchronizationInfo

if updateAuthenticationInfo.ResynchronizationInfo != nil {
	logger.UeAuthPostLog.Warningln("Auts: ", updateAuthenticationInfo.ResynchronizationInfo.Auts)
	ausfCurrentSupi := ausf_context.GetSupiFromSuciSupiMap(supiOrSuci)
	logger.UeAuthPostLog.Warningln(ausfCurrentSupi)
	ausfCurrentContext := ausf_context.GetAusfUeContext(ausfCurrentSupi)
	logger.UeAuthPostLog.Warningln(ausfCurrentContext.Rand)
	updateAuthenticationInfo.ResynchronizationInfo.Rand = ausfCurrentContext.Rand
	logger.UeAuthPostLog.Warningln("Rand: ", updateAuthenticationInfo.ResynchronizationInfo.Rand)
	authInfoReq.ResynchronizationInfo = updateAuthenticationInfo.ResynchronizationInfo
}

    实例化 var authInfoReq models.AuthenticationInfoRequest,并赋值,猜测应该是向 UDM 请求的 body 

type AuthenticationInfoRequest struct {
	SupportedFeatures     string                 `json:"supportedFeatures,omitempty" yaml:"supportedFeatures" bson:"supportedFeatures" mapstructure:"SupportedFeatures"`
	ServingNetworkName    string                 `json:"servingNetworkName" yaml:"servingNetworkName" bson:"servingNetworkName" mapstructure:"ServingNetworkName"`
	ResynchronizationInfo *ResynchronizationInfo `json:"resynchronizationInfo,omitempty" yaml:"resynchronizationInfo" bson:"resynchronizationInfo" mapstructure:"ResynchronizationInfo"`
	AusfInstanceId        string                 `json:"ausfInstanceId" yaml:"ausfInstanceId" bson:"ausfInstanceId" mapstructure:"AusfInstanceId"`
}

   2.3 AUSF 向 UDM 请求SUPI / SUCI 的身份验证信息数据

    NF 服务使用者(AUSF)从 UDM 请求 SUPI / SUCI 的身份验证信息数据。 如果提供了 SUCI,则 UDM 根据 SUCI 计算 SUPI(请参阅3GPP TS 33.501 [6])。 如果选择了 5G AKA 或 EAP-AKA',则 UDM 会考虑从 NF 服务使用者(AUSF)接收到的信息以及该资源的当前表示来计算认证向量。 有关详细信息,请参见 3GPP TS 33.501 [6]。

    GenerateAuthData 向 UDM 发送请求,/nudm-ueau/v1/{udId}/security-information/generate-auth-data

udmUrl := getUdmUrl(self.NrfUri)
client := createClientToUdmUeau(udmUrl)
authInfoResult, _, err := client.GenerateAuthDataApi.GenerateAuthData(context.Background(), supiOrSuci, authInfoReq)
if err != nil {
	logger.UeAuthPostLog.Infoln(err.Error())
	var problemDetails models.ProblemDetails
	if authInfoResult.AuthenticationVector == nil {
		problemDetails.Cause = "AV_GENERATION_PROBLEM"
	} else {
		problemDetails.Cause = "UPSTREAM_SERVER_ERROR"
	}
	problemDetails.Status = http.StatusInternalServerError
	return nil, "", &problemDetails
}
/nudm-ueau/v1/{udId}/security-information/generate-auth-data

 

 

3. UDM 处理 AUSF 的身份验证信息数据请求

    /:supiOrSuci/security-information/generate-auth-data

       -->  HttpGenerateAuthData

                -->  HandleGenerateAuthDataRequest

                         -->  GenerateAuthDataProcedure

    如果提供了 SUCI,则 UDM 根据 SUCI 计算 SUPI(请参阅3GPP TS 33.501 [6])。 如果选择了 5G AKA 或 EAP-AKA',则 UDM 会考虑从 NF 服务使用者(AUSF)接收到的信息以及该资源的当前表示来计算认证向量。 有关详细信息,请参见 3GPP TS 33.501 [6]。

func GenerateAuthDataProcedure(authInfoRequest models.AuthenticationInfoRequest, supiOrSuci string) (
	response *models.AuthenticationInfoResult, problemDetails *models.ProblemDetails) {
	logger.UeauLog.Traceln("In GenerateAuthDataProcedure")

	response = &models.AuthenticationInfoResult{}
	rand.Seed(time.Now().UnixNano())
	supi, err := suci.ToSupi(supiOrSuci)

   3.1 UDM 向 UDR 查询鉴权数据

    /subscription-data/{ueId}/authentication-data/authentication-subscription, 包括 OP  OPC  K  SQN

client := createUDMClientToUDR(supi, false)
authSubs, _, err := client.AuthenticationDataDocumentApi.QueryAuthSubsData(context.Background(), supi, nil)
if err != nil {
	problemDetails = &models.ProblemDetails{
		Status: http.StatusForbidden,
		Cause:  authenticationRejected,
		Detail: err.Error(),
	}

	logger.UeauLog.Errorln("Return from UDR QueryAuthSubsData error")
	return nil, problemDetails
}

  { "_id" : ObjectId("5fb4baa6ea01aa3a37fd5d96"), "sequenceNumber" : "000000000022", "authenticationManagementField" : "8000", "milenage" : { "op" : { "opValue" : "c9e8763286b5b9ffbdf56e1297d0887b", "encryptionAlgorithm" : 0, "encryptionKey" : 0 } }, "opc" : { "opcValue" : "981d464c7c52eb6e5036234984ad0bcf", "encryptionAlgorithm" : 0, "encryptionKey" : 0 }, "ueId" : "imsi-2089300007487", "authenticationMethod" : "5G_AKA", "permanentKey" : { "encryptionAlgorithm" : 0, "encryptionKey" : 0, "permanentKeyValue" : "5122250214c33e723a5dd523fc145fc0" } }

 /subscription-data/{ueId}/authentication-data/authentication-subscription UDR->UDM response 

 

   3.2 AMF 硬编码 8000(Authentication Management Field)

AMF, err := hex.DecodeString("8000")
if err != nil {
	problemDetails = &models.ProblemDetails{
		Status: http.StatusForbidden,
		Cause:  authenticationRejected,
		Detail: err.Error(),
	}

	logger.UeauLog.Errorln("err", err)
	return nil, problemDetails
}

   3.3 需要重新同步的情况

// re-synchroniztion
if authInfoRequest.ResynchronizationInfo != nil {
	Auts, deCodeErr := hex.DecodeString(authInfoRequest.ResynchronizationInfo.Auts)
	if deCodeErr != nil {
		problemDetails = &models.ProblemDetails{
			Status: http.StatusForbidden,
			Cause:  authenticationRejected,
			Detail: deCodeErr.Error(),
		}

		logger.UeauLog.Errorln("err", deCodeErr)
		return nil, problemDetails
	}

   3.4 对 SQN 加一处理,并重新存储

// increment sqn
bigSQN := big.NewInt(0)
sqn, err = hex.DecodeString(sqnStr)
if err != nil {
	problemDetails = &models.ProblemDetails{
		Status: http.StatusForbidden,
		Cause:  authenticationRejected,
		Detail: err.Error(),
	}

	logger.UeauLog.Errorln("err", err)
	return nil, problemDetails
}

bigSQN.SetString(sqnStr, 16)

bigInc := big.NewInt(1)
bigSQN = bigInc.Add(bigSQN, bigInc)

SQNheStr := fmt.Sprintf("%x", bigSQN)
SQNheStr = strictHex(SQNheStr, 12)
patchItemArray := []models.PatchItem{
	{
		Op:    models.PatchOperation_REPLACE,
		Path:  "/sequenceNumber",
		Value: SQNheStr,
	},
}
Figure 7: Generation of authentication vectors
  •      MAC = f1K(SQN || RAND || AMF) 
  •      XRES = f2K (RAND)
  •      CK = f3K (RAND)
  •      IK = f4K (RAND)
  •      AK = f5K (RAND)     
  •      AUTN = SQN Å AK || AMF || MAC
// Generate macA, macS
err = milenage.F1(opc, k, RAND, sqn, AMF, macA, macS)
if err != nil {
	logger.UeauLog.Errorln("milenage F1 err ", err)
}

     f1 函数生成 macA 和 macS

* milenage_f1 - Milenage f1 and f1* algorithms
* @opc: OPc = 128-bit value derived from OP and K
* @k: K = 128-bit subscriber key
* @_rand: RAND = 128-bit random challenge
* @sqn: SQN = 48-bit sequence number
* @amf: AMF = 16-bit authentication management field
* @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
* @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL

   3.5 生成 AUTN 

// Generate RES, CK, IK, AK, AKstar
// RES == XRES (expected RES) for server
err = milenage.F2345(opc, k, RAND, RES, CK, IK, AK, AKstar)
if err != nil {
	logger.UeauLog.Errorln("milenage F2345 err ", err)
}
// fmt.Printf("milenage RES = %s\n", hex.EncodeToString(RES))

// Generate AUTN
// fmt.Printf("SQN=%x\nAK =%x\n", SQN, AK)
// fmt.Printf("AMF=%x, macA=%x\n", AMF, macA)
SQNxorAK := make([]byte, 6)
for i := 0; i < len(sqn); i++ {
	SQNxorAK[i] = sqn[i] ^ AK[i]
}
// fmt.Printf("SQN xor AK = %x\n", SQNxorAK)
AUTN := append(append(SQNxorAK, AMF...), macA...)
fmt.Printf("AUTN = %x\n", AUTN)
UDM->AUSF response security-information/generate-auth-data

 

4. AUSF 向 AMF response ue-authentications 

   4.1 AUSF 根据 XRES* 推导出 HXRES*

locationURI := self.Url + "/nausf-auth/v1/ue-authentications/" + supiOrSuci
putLink := locationURI
if authInfoResult.AuthType == models.AuthType__5_G_AKA {
	logger.UeAuthPostLog.Infoln("Use 5G AKA auth method")
	putLink += "/5g-aka-confirmation"

	// Derive HXRES* from XRES*
	concat := authInfoResult.AuthenticationVector.Rand + authInfoResult.AuthenticationVector.XresStar
	var hxresStarBytes []byte
	if bytes, err := hex.DecodeString(concat); err != nil {
		logger.Auth5gAkaComfirmLog.Warnf("decode error: %+v", err)
	} else {
		hxresStarBytes = bytes
	}
	hxresStarAll := sha256.Sum256(hxresStarBytes)
	hxresStar := hex.EncodeToString(hxresStarAll[16:]) // last 128 bits
	logger.Auth5gAkaComfirmLog.Infof("XresStar = %x\n", authInfoResult.AuthenticationVector.XresStar)

   4.2 AUSF 根据 Kausf 推导出 Kseaf 

// Derive Kseaf from Kausf
Kausf := authInfoResult.AuthenticationVector.Kausf
var KausfDecode []byte
if ausfDecode, err := hex.DecodeString(Kausf); err != nil {
	logger.Auth5gAkaComfirmLog.Warnf("AUSF decode failed: %+v", err)
} else {
	KausfDecode = ausfDecode
}
P0 := []byte(snName)
Kseaf := UeauCommon.GetKDFValue(KausfDecode, UeauCommon.FC_FOR_KSEAF_DERIVATION, P0, UeauCommon.KDFLen(P0))
ausfUeContext.XresStar = authInfoResult.AuthenticationVector.XresStar
ausfUeContext.Kausf = Kausf
ausfUeContext.Kseaf = hex.EncodeToString(Kseaf)
ausfUeContext.Rand = authInfoResult.AuthenticationVector.Rand

   AUSF 存储上下文,只给 AMF 返回 Rand Autn HxresStar

AUSF 向 AMF response ue-authentications 

 

5. AMF 向 UE 发送 Authentication Request

    Gmm 消息类型为 MsgTypeAuthenticationRequest,包裹的 NGAP 消息为 DownlinkNASTransport

AMF->UE DownlinkNASTransport, Authentication request

 

6. UE 向 AMF 发送 Authentication response

  •     接收到 RAND 和 AUTN, USIM 首先计算匿名密钥 AK = f5K (RAND),以及检索 SQN = SQN = (SQN Å AK) Å AK
  •     USIM 计算 f1K (SQN || RAND || AMF),比较 MAC 和 在 AUTN 的 MAC,如果不相同,UE 将验证失败消息发送回 VLR / SGSN,并说明原因,然后用户放弃该过程。
  •     接下来,USIM 验证接收到的序列号 SQN 在正确范围内。
  •     如果 USIM 认为序列号不在正确的范围内,则会将同步失败(包括适当的参数)发送回VLR / SGSN,并放弃该过程。
UE->AMF UplinkNASTransport,Authentication request

   6.1 UE 向 AMF 发送 Authentication response 同步失败

UE->AMF UplinkNASTransport,Authentication failure (Synch failure)

    6.1.1 AMF 处理 Authentication request Synch failure 

func HandleAuthenticationFailure(ue *context.AmfUe, anType models.AccessType,
	authenticationFailure *nasMessage.AuthenticationFailure) error {

	logger.GmmLog.Info("[AMF] Handle Authentication Failure")

	util.StopT3560(ue)

   可以看到处理的失败原因包括: 

  • Cause5GMMMACFailure
  • Cause5GMMNon5GAuthenticationUnacceptable
  • Cause5GMMngKSIAlreadyInUse
  • Cause5GMMSynchFailure

    对于 Synch failure 的情况处理,超过两次则 reject 处理

case nasMessage.Cause5GMMSynchFailure: // TS 24.501 5.4.1.3.7 case f
	logger.GmmLog.Warn("Authentication Failure 5GMM Cause: Synch Failure")

	ue.AuthFailureCauseSynchFailureTimes++
	if ue.AuthFailureCauseSynchFailureTimes >= 2 {
		logger.GmmLog.Warnf("2 consecutive Synch Failure, terminate authentication procedure")
		gmm_message.SendAuthenticationReject(ue.RanUe[anType], "")
		return GmmFSM.SendEvent(ue.State[anType], AuthFailEvent, fsm.ArgsType{ArgAmfUe: ue, ArgAccessType: anType})
	}

    6.1.1.1 SendUEAuthenticationAuthenticateRequest 重新向 AUSF 发送鉴权请求

AMF->AUSF request ue-authentications

    则进入第 2 章节进行处理, 这次包含 resynchronizationInfo 的处理  

 

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值