freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

基于free5gc+UERANSIM的5G注册管理流程及安全服务分析 下
2021-11-24 09:54:42

一、前言

随着5G的快速建设,5G的安全问题受到越来越多的关注。本篇作为《基于free5gc+UERANSIM的5G注册管理流程及安全服务分析 上》的姊妹篇,基于模拟环境对《3GPP TS 33.501》中定义的相关安全服务进行详细分析。旨在为5G安全研究及测试人员提供参考。

二、5G安全服务介绍

3GPP 5G的协议标准种类繁多,其中与安全紧密相关的协议标准是5G系统安全架构和流程(3GPP TS 33.501),该协议规定了5G系统和5G核心的安全特性和安全机制,以及5G系统内包括5G核心和5G新无线在内的安全流程。

《3GPP TS 33.501》标准14章定义了安全相关服务,这些服务为5G网络提供鉴权认证等安全相关的功能。其中和用户注册管理流程相关的有Nausf_UEAuthentication、Nudm_UEAuthentication以及Nudm_UEAuthentication_ResultConfirm。

三、模拟环境介绍

本节简单介绍了UERANSIM+free5gc环境,用户可以通过使用arp、ifconfig、docker inspect及网桥brctl 相关命令,来收集容器IP及Mac地址相关信息,绘制的组网示意图如下:

1637717462_619d95d68206002441df3.png!small?1637717454042

如上图所示:环境基于ubuntu 20.04 VMware虚机部署,5gc网元分别部署在虚机的docker容器中。5gc各模拟网元与模拟RAN 通过虚拟网桥进行数据交换。物理机上的VMware 虚拟网卡作为DN(互联网节点)通过虚拟网桥与容器中的UPF对接。详细的搭建方法可以参考沉烽网络安全实验室的文章《free5gc+UERANSIM模拟5G网络环境搭建及基本使用》 。

四、安全服务分析

本章节主要介绍注册管理流程相关的安全服务,并对流量、源代码进行分析,其中包括AUSF网元的Nausf_UEAuthentication服务,UDM网元的Nudm_UEAuthentication服务以及Nudm_UEAuthentication_ResultConfirm服务。

4.1、AUSF安全服务流量及代码分析

4.1.1 Nausf_UEAuthentication服务介绍

AUSF通过Nausf_UEAuthentication安全服务向请求者NF提供UE的认证服务,验证UE并提供相关的密钥资料,AMF会使用这些密钥来派生后续密钥。5GAKA认证中,AMF通过提供UE相关信息和服务网络名称来请求UE的身份验证,然后,NF服务消费者应将从UE收到的结果返回给AUSF进行XRES和HXRES的验证,具体定义可参考《3GPP TS 33.501 V16.5.0》标准。 服务输入:1、在初始身份验证请求中:SUPI或者SUCI,网络服务名称。 2、后续的认证请求中,AUSF从UDM中检索UE的签约身份验证方法,并根据UDM提供的信息,AUSF进入5G-AKA或者EAP-based authentication,两种鉴权方法的的输入分别如下。 a.5G AKA:带有RES*的鉴权信息或者失败信息,以及其他相关信息(比如RAND/AUTS)。 b.EAP-AKA':RFC 4187[21]和RFC5448[12]以及附件中描述的EAP数据包。 服务输出:1、Nausf_UEAuthentication将根据认证方式的不同输出一下内容之一。 a.5G AKA:认证向量。 b.EAP-AKA':RFC 4187[21]和RFC5448[12]以及附件中描述的EAP数据包。 2、认证结果,如果认证成功,则为AMF用于导出NAS安全密钥和其他。

4.1.2 Nausf_UEAuthentication服务流量及代码分析

Nausf_UE_Authentication请求一处理过程AMF收到RAN侧发送来的UE注册请求,如果AMF中不存在UE的安全上下文,则会向AUSF发起Nausf_UE_Authentication请求,该请求报文如下,报文包含了SUPI或者SUCI以及网络服务名称,对应标准中的描述。1637717489_619d95f1819ad67e6d175.png!small?1637717481045

{
"supiOrSuci": "suci-0-208-93-0000-0-0-0000000003",
"servingNetworkName": "5G:mnc093.mcc208.3gppnetwork.org"
}

从free5gc的代码中的路由配置可以找到Nausf_UEAuthentication安全服务的处理函数为HTTPUeAuthenticationsPost。

var routes = Routes{    
{
"HTTPUeAuthenticationsPost",
strings.ToUpper("Post"),
"/ue-authentications",
HTTPUeAuthenticationsPost,
}
}

HTTPUeAuthenticationsPost函数将调用HandleUeAuthPostRequest处理AMF发送的请求报文,并使用ctx.Data方法发送响应报文给AMF网元。

// HTTPUeAuthenticationsPost -
func HTTPUeAuthenticationsPost(ctx *gin.Context) {
...
req := http_wrapper.NewRequest(ctx.Request, authInfo)
rsp := producer.HandleUeAuthPostRequest(req)
for key, value := range rsp.Header {
ctx.Header(key, value[0])
}
responseBody, err := openapi.Serialize(rsp.Body, "application/json")
if err != nil {
logger.UeAuthPostLog.Errorln(err)
problemDetails := models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause:  "SYSTEM_FAILURE",
Detail: err.Error(),
}
ctx.JSON(http.StatusInternalServerError, problemDetails)
} else {
ctx.Data(rsp.Status, "application/json", responseBody)
}
}

进入HandleUeAuthPostRequest方法后,会调用UeAuthPostRequestProcedure方法处理,该函数将返回response并通过http_wrapper.NewResponse进行封装,返回给上层函数。

func HandleUeAuthPostRequest(request *http_wrapper.Request) *http_wrapper.Response {
logger.UeAuthPostLog.Infof("HandleUeAuthPostRequest")
updateAuthenticationInfo := request.Body.(models.AuthenticationInfo)

response, locationURI, problemDetails := UeAuthPostRequestProcedure(updateAuthenticationInfo)
respHeader := make(http.Header)
respHeader.Set("Location", locationURI)

if response != nil {
return http_wrapper.NewResponse(http.StatusCreated, respHeader, response)
} else if problemDetails != nil {
return http_wrapper.NewResponse(int(problemDetails.Status), nil, problemDetails)
}
problemDetails = &models.ProblemDetails{
Status: http.StatusForbidden,
Cause:  "UNSPECIFIED",
}
return http_wrapper.NewResponse(http.StatusForbidden, nil, problemDetails)
}

UeAuthPostRequestProcedure方法会根据snname对报文进行鉴权验证,如果服务网络没有被授权,则AUSF会返回带有“SERVING_NETWORK_NOT_AUTHORIZE”的403报文。

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

supiOrSuci := updateAuthenticationInfo.SupiOrSuci

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")
}

free5gc中该函数通过正则表达式对ServingNetworkName参数进行验证,ausf/context/context.go中的关联代码如下,snRegex变量为验证ServingNetworkName的正则表达式。

func Init() {
if snRegex, err := regexp.Compile("5G:mnc[0-9]{3}[.]mcc[0-9]{3}[.]3gppnetwork[.]org");
err != nil {
logger.ContextLog.Warnf("SN compile error: %+v", err)
} else {
ausfContext.snRegex = snRegex
}
InitAusfContext(&ausfContext)
}
func IsServingNetworkAuthorized(lookup string) bool {
if ausfContext.snRegex.MatchString(lookup) {
return true
} else {
return false
}
}

接下来AUSF为了响应AMF的UeAuthPostRequestProcedure请求会使用GET方法从NRF网元获取udm的相关信息。向NRF网元发送的GET请求会携带requester-nf-type、service-names、target-fn-type参数。1637717512_619d960842e599b05e7ba.png!small?1637717503788free5gc项目中对应的代码及getUdmUrl函数如下。

func getUdmUrl(nrfUri string) string {
udmUrl := "https://localhost:29503" // default
nfDiscoverParam := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{
ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NUDM_UEAU}),
}
res, err := consumer.SendSearchNFInstances(nrfUri, models.NfType_UDM, models.NfType_AUSF, nfDiscoverParam)
if err != nil {
logger.UeAuthPostLog.Errorln("[Search UDM UEAU] ", err.Error())
} else if len(res.NfInstances) > 0 {
udmInstance := res.NfInstances[0]
if len(udmInstance.Ipv4Addresses) > 0 && udmInstance.NfServices != nil {
ueauService := (*udmInstance.NfServices)[0]
ueauEndPoint := (*ueauService.IpEndPoints)[0]
udmUrl = string(ueauService.Scheme) + "://" + ueauEndPoint.Ipv4Address + ":" + strconv.Itoa(int(ueauEndPoint.Port))
}
} else {
logger.UeAuthPostLog.Errorln("[Search UDM UEAU] len(NfInstances) = 0")
}
return udmUrl
}

udmUrl := getUdmUrl(self.NrfUri)

NRF会根据参数返回在线的UDM实例地址,以下json报文中给出部分返回信息以供参考。1637717528_619d9618e8de8ca2e0c48.png!small?1637717520473

{
"validityPeriod": 100,
"nfInstances": [
{
"nfInstanceId": "922afb33-bf96-471a-8609-16cee6be4a4d",
"nfType": "UDM",
"nfStatus": "REGISTERED",
"plmnList": [],
"ipv4Addresses": [],
"udmInfo": { },
"nfServices": [
{
"serviceInstanceId": "4",
"serviceName": "nudm-pp",
"versions": [],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [],
"apiPrefix": "http://udm.free5gc.org:8000"
}
]
}
]
}

获取数据后,AUSF将向UDM发送generate-auth-data的请求以获取鉴权向量和其他相关数据,该报文的参数为servingNetworkName以及ausfInstanceId。

1637717573_619d9645eb43f10a5ebbf.png!small?1637717565459

{
"servingNetworkName": "5G:mnc093.mcc208.3gppnetwork.org",
"ausfInstanceId": "e7218bdf-9541-4917-907e-c3f096fb941e"
}

该部分对应的代码如下。

client := createClientToUdmUeau(udmUrl)
authInfoResult, rsp, err := client.GenerateAuthDataApi.GenerateAuthData(context.Background(), supiOrSuci, authInfoReq)

UDM会根据入参与本地对应的PermanentKey计算五元组(RAND,AUTH,RES,CK,IK),并生成5G_AKA中的authenticationVector(AV)鉴权向量(RAND,AUTH,XRES*,Kausf),用于对UE进行双向认证。该UDM服务将会在下文中详细分析。以下为UDM返回给AUSF的报文及json数据。1637717591_619d96572ff66270f7ece.png!small?1637717582694

{
"authType": "5G_AKA",
"5gAuthData": {
"rand": "e37a60c2a71676fa504d531f5103e03f",
"hxresStar": "9ba762a79f2f97cdebf1cc952f2af418",
"autn": "40bd72e10f7d8000a233aa3b112b0979"
},
"_links": {
"link": {
"href": "http://ausf.free5gc.org:8000/nausf-auth/v1/ue-authentications/suci-0-208-93-0000-0-0-0000000003/5g-aka-confirmation"
}
},
"servingNetworkName": "5G:mnc093.mcc208.3gppnetwork.org"
}

AUSF接收到报文后首先AUSF将根据authType字段判断鉴权协议类型,在free5gc中使用的是5G_AKA协议。AUSF会根据RAND以及XRES进行sha256哈希计算HXRES。接下来将通过Kausf计算Kseaf,将XRES*、Kausf、Kseaf、Rand保存到上下文中。

// 根于supi拿到authInfoResult
authInfoResult, rsp, err := client.GenerateAuthDataApi.GenerateAuthData(context.Background(), supiOrSuci, authInfoReq)

if authInfoResult.AuthType == models.AuthType__5_G_AKA {
logger.UeAuthPostLog.Infoln("Use 5G AKA auth method")
putLink += "/5g-aka-confirmation"

// 通过XRES 计算HXRES;通过udm发送给ausf认证向量AV中的RAND和XRES进行SHA256计算得到HXRES
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)

// 通过Kausf计算Kseaf,将kuasf,0x6c常量,服务网络P0作为入参,计算Kseaf。
// 同时ausf将Ksauf、XRES和RAND作为上下文进行保存。
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))
//将XRES*、Kausf、Kseaf、Rand保存到上的下文中
ausfUeContext.XresStar = authInfoResult.AuthenticationVector.XresStar
ausfUeContext.Kausf = Kausf
ausfUeContext.Kseaf = hex.EncodeToString(Kseaf)
ausfUeContext.Rand = authInfoResult.AuthenticationVector.Rand
}

AUSF将,然后将新的AV(RAND,AUTH,HXRES*)以及其他相关信息放在Nausf_UE_Authentication的响应报文中发送给AMF网元进行双向认证。1637717752_619d96f81b337049af57b.png!small?1637717743633

{
"authType": "5G_AKA",
"5gAuthData": {
"rand": "e37a60c2a71676fa504d531f5103e03f",
"hxresStar": "9ba762a79f2f97cdebf1cc952f2af418",
"autn": "40bd72e10f7d8000a233aa3b112b0979"
},
"_links": {
"link": {
"href": "http://ausf.free5gc.org:8000/nausf-auth/v1/ue-authentications/suci-0-208-93-0000-0-0-0000000003/5g-aka-confirmation"
}
},
"servingNetworkName": "5G:mnc093.mcc208.3gppnetwork.org"
}

封装Nausf_UE_Authentication的代码如下。

//封装Nausf_UE_Authentication返回报文
var av5gAka models.Av5gAka
av5gAka.Rand = authInfoResult.AuthenticationVector.Rand
av5gAka.Autn = authInfoResult.AuthenticationVector.Autn
av5gAka.HxresStar = hxresStar
responseBody.Var5gAuthData = av5gAka

linksValue := models.LinksValueSchema{Href: putLink}
responseBody.Links = make(map[string]models.LinksValueSchema)
responseBody.Links["5g-aka"] = linksValue

Nausf_UE_Authentication请求二处理过程AMF完成鉴权后,会发送5g-aka-confirmation报文给AUSF的Nausf_UE_Authentication服务,该报文类型为PUT,body数据中包含了UE的RES*信息。1637717764_619d9704aa008dbbf3628.png!small?1637717756185

{
"resStar": "c094c8af16226e35962fab5d15aff080"
}

根据AUSF代码中的路由信息,可看到该请求处理函数为HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut。

var routes = Routes{
{
"HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut",
strings.ToUpper("Put"),
"/ue-authentications/:authCtxId/5g-aka-confirmation",
HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut,
}
}

HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut函数会对报文进行反序列化并调用HandleAuth5gAkaComfirmRequest处理请求信息并将返回报文通过ctx.Data发送给AMF。

func HTTPUeAuthenticationsAuthCtxID5gAkaConfirmationPut(ctx *gin.Context) {
var confirmationData models.ConfirmationData

requestBody, err := ctx.GetRawData()
...//略过错误处理
req := http_wrapper.NewRequest(ctx.Request, confirmationData)
req.Params["authCtxId"] = ctx.Param("authCtxId")
rsp := producer.HandleAuth5gAkaComfirmRequest(req)
responseBody, err := openapi.Serialize(rsp.Body, "application/json")
if err != nil {
logger.Auth5gAkaComfirmLog.Errorln(err)
problemDetails := models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause:  "SYSTEM_FAILURE",
Detail: err.Error(),
}
ctx.JSON(http.StatusInternalServerError, problemDetails)
} else {
ctx.Data(rsp.Status, "application/json", responseBody)
}
}

HandleAuth5gAkaComfirmRequest函数最终通过Auth5gAkaComfirmRequestProcedure进行处理,并使用http_wrapper.NewResponse封装消息体。

func HandleAuth5gAkaComfirmRequest(request *http_wrapper.Request) *http_wrapper.Response {
logger.Auth5gAkaComfirmLog.Infof("Auth5gAkaComfirmRequest")
updateConfirmationData := request.Body.(models.ConfirmationData)
ConfirmationDataResponseID := request.Params["authCtxId"]

response, problemDetails := Auth5gAkaComfirmRequestProcedure(updateConfirmationData, ConfirmationDataResponseID)
if response != nil {
return http_wrapper.NewResponse(http.StatusOK, nil, response)
} else if problemDetails != nil {
return http_wrapper.NewResponse(int(problemDetails.Status), nil, problemDetails)
}
problemDetails = &models.ProblemDetails{
Status: http.StatusForbidden,
Cause:  "UNSPECIFIED",
}
return http_wrapper.NewResponse(http.StatusForbidden, nil, problemDetails)
}

Auth5gAkaComfirmRequestProcedure将使用Compare函数对比上下文中存储的Xres以及AMF请求报文中的Res。如果对比成功,则鉴权成功,并设置AuthResult为models.AuthResult_SUCCESS,对比失败设置AuthResult为models.AuthResult_FAILURE。

func Auth5gAkaComfirmRequestProcedure(updateConfirmationData models.ConfirmationData,
ConfirmationDataResponseID string) (*models.ConfirmationDataResponse, *models.ProblemDetails) {
logger.Auth5gAkaComfirmLog.Infof("res*: %x\nXres*: %x\n", updateConfirmationData.ResStar, ausfCurrentContext.XresStar)
if strings.Compare(updateConfirmationData.ResStar, ausfCurrentContext.XresStar) == 0 {
ausfCurrentContext.AuthStatus = models.AuthResult_SUCCESS
responseBody.AuthResult = models.AuthResult_SUCCESS
success = true
logger.Auth5gAkaComfirmLog.Infoln("5G AKA confirmation succeeded")
responseBody.Kseaf = ausfCurrentContext.Kseaf
} else {
ausfCurrentContext.AuthStatus = models.AuthResult_FAILURE
responseBody.AuthResult = models.AuthResult_FAILURE
logConfirmFailureAndInformUDM(ConfirmationDataResponseID, models.AuthType__5_G_AKA, servingNetworkName,
"5G AKA confirmation failed", ausfCurrentContext.UdmUeauUrl)
}

}

AUSF完成鉴权后会将鉴权结果、时间戳、认证类型、servingNetworkName等信息发送给UDM网元。

1637717789_619d971d8f5fa1cf730a1.png!small?1637717781096

{
"nfInstanceId": "",
"success": true,
"timeStamp": "2021-09-24T08:28:53.330400908Z",
"authType": "5G_AKA",
"servingNetworkName": "5G:mnc093.mcc208.3gppnetwork.org"
}

发送鉴权结果报文及错误处理的代码如下。

if sendErr := sendAuthResultToUDM(currentSupi, models.AuthType__5_G_AKA, success, servingNetworkName,ausfCurrentContext.UdmUeauUrl); 
sendErr != nil {
logger.Auth5gAkaComfirmLog.Infoln(sendErr.Error())
var problemDetails models.ProblemDetails
problemDetails.Status = http.StatusInternalServerError
problemDetails.Cause = "UPSTREAM_SERVER_ERROR"
return nil, &problemDetails
}

UDM接收请求后会响应201报文。

1637717800_619d9728ae10a42bfbd70.png!small?1637717792227

接下来AUSF将发送响应报文给AMF网元,响应报文中包含了AMF的鉴权结果、supi、kseaf等信息。

1637717809_619d97318a67fb10600c9.png!small?1637717801065

{
"authResult": "AUTHENTICATION_SUCCESS",
"supi": "imsi-208930000000003",
"kseaf": "b0c417e1aa5e795f6b9f73946def0ef8970e24a8b648a3de6f58b94c02e05451"
}

4.2、UDM网元安全服务流量及代码分析

对于Nudm_UEAuthentication服务,协议定义了以下两个操作

  1. Nudm_UEAuthentication_GET

  2. Nudm_UEAuthentication_ResultConfirmation

4.2.1 Nudm_UEAuthentication服务介绍

该服务的主要作用是AUSF将需要认证UE的SUCI发送给UDM,来请求UDM选择一种身份验证方法,根据所选验证方法计算身份验证向量(HE AV),最后从UDM那里获取到身份验证向量。如果AUSF的请求中携带了SUCI,那么UDM将会返回SUPI给AUSF。具体定义可参考《3GPP TS 33.501 V16.5.0》标准。

服务输入:

可以是SUPI或者是SUCI,以及服务网络名称。

服务输出:

身份认证的方式、身份认证的数据(HE AV)以及SUPI。

4.2.2 Nudm_UEAuthentication服务流量及代码分析

在free5gc模拟环境中截获AUSF向UDM请求的报文如下:

1637718073_619d9839623b2d02fea9b.png!small?1637718065040

从报文里可以看到AUSF的确发送SUCI给了UDM,POST请求体中携带了如下数据:

{
"servingNetworkName": "5G:mnc093.mcc208.3gppnetwork.org",
"ausfInstanceId": "e7218bdf-9541-4917-907e-c3f096fb941e"
}

分别对应的是服务网络名称和AUSF的InstanceId。

接着在free5gc模拟环境中截获UDM向AUSF返回的报文如下:

1637718084_619d9844c8f398584c176.png!small?1637718076440

消息体中携带的数据如下:

{
"authType": "5G_AKA",
"authenticationVector": {
"avType": "",
"rand": "e37a60c2a71676fa504d531f5103e03f",
"xres": "",
"autn": "40bd72e10f7d8000a233aa3b112b0979",
"ckPrime": "",
"ikPrime": "",
"xresStar": "c094c8af16226e35962fab5d15aff080",
"kausf": "a210bdcdc9cde9d6d9e4447c1b5a0491d291a09378a22ef76526574601f3cd6e"
},
"supi": "imsi-208930000000003"
}

从报文中可以看到UDM告知AUSF本次身份认证的方式为5G-AKA,传递给AUSF需要的身份验证向量(HE AV)和SUPI。

整个服务过程和协议描述保持一致。

产生AV向量的代码定位于\udm\producer\generate_auth_data.go中的GenerateAuthDataProcedure函数,以下为相关代码分析。

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())
//将AUSF发送过来的SUCI解密为SUPI
supi, err := suci.ToSupi(supiOrSuci, udm_context.UDM_Self().SuciProfiles)

//根据SUPI找到认证对象
authSubs, res, 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
}

//从认证对象中取出sqn
sqnStr := strictHex(authSubs.SequenceNumber, 12)
logger.UeauLog.Traceln("sqnStr", sqnStr)
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
}

//生成RAND参数
RAND := make([]byte, 16)
_, err = cryptoRand.Read(RAND)

//AMF硬编码8000
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
}

//从认证对象中取出opc参数
if authSubs.Opc != nil && authSubs.Opc.OpcValue != "" {
opcStr = authSubs.Opc.OpcValue
if len(opcStr) == opcStrLen {
opc, err = hex.DecodeString(opcStr)
if err != nil {
logger.UeauLog.Errorln("err", err)
} else {
hasOPC = true
}
} else {
logger.UeauLog.Errorln("opcStr length is ", len(opcStr))
}
} else {
logger.UeauLog.Infoln("Nil Opc")
}

//取出PermanentKey
if authSubs.PermanentKey != nil {
kStr = authSubs.PermanentKey.PermanentKeyValue
if len(kStr) == keyStrLen {
k, err = hex.DecodeString(kStr)
if err != nil {
logger.UeauLog.Errorln("err", err)
} else {
hasK = true
}

//计算摘要
err = milenage.F1(opc, k, RAND, sqn, AMF, macA, macS)
if err != nil {
logger.UeauLog.Errorln("milenage F1 err ", err)

// 计算 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)
}

//计算AUTH
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)

// 计算 XRES*
key := append(CK, IK...)
FC := UeauCommon.FC_FOR_RES_STAR_XRES_STAR_DERIVATION
P0 := []byte(authInfoRequest.ServingNetworkName)
P1 := RAND
P2 := RES

kdfValForXresStar := UeauCommon.GetKDFValue(
key, FC, P0, UeauCommon.KDFLen(P0), P1, UeauCommon.KDFLen(P1), P2, UeauCommon.KDFLen(P2))
xresStar := kdfValForXresStar[len(kdfValForXresStar)/2:]

// 计算 Kausf
FC = UeauCommon.FC_FOR_KAUSF_DERIVATION
P0 = []byte(authInfoRequest.ServingNetworkName)
P1 = SQNxorAK
kdfValForKausf := UeauCommon.GetKDFValue(key, FC, P0, UeauCommon.KDFLen(P0), P1, UeauCommon.KDFLen(P1))

// 填充 rand, xresStar, autn, kausf
av.Rand = hex.EncodeToString(RAND)
av.XresStar = hex.EncodeToString(xresStar)
av.Autn = hex.EncodeToString(AUTN)
av.Kausf = hex.EncodeToString(kdfValForKausf)

4.2.3 Nudm_UEAuthentication_ResultConfirm服务介绍

Nudm_UEAuthentication_ResultConfirm服务的主要作用是AUSF用来告知UDM本次UE身份验证的结果,具体定义可参考《3GPP TS 33.501 V16.5.0》协议中的相关章节。

服务输入:

SUPI、身份验证的时间戳、身份验证类型以及服务网络名称。

5.2.4 Nudm_UEAuthentication_ResultConfirm服务流量及代码分析

在free5gc模拟环境中截获AUSF向UDM返回的报文如下:

1637718100_619d985453a599433d599.png!small?1637718091909

报文中携带了本次验证UE的SUPI信息。

消息体中携带的数据如下:

{
"nfInstanceId": "",
"success": true,
"timeStamp": "2021-09-24T08:28:53.330400908Z",
"authType": "5G_AKA",
"servingNetworkName": "5G:mnc093.mcc208.3gppnetwork.org"
}

通过这个报文可以看到本次认证的结果是成功的,并且携带了认证的时间戳,认证的方式和服务网络名称。

整个服务的过程和协议描述一致。

代码定位于ausf\producer\functions.go中的sendAuthResultToUDM函数

func sendAuthResultToUDM(id string, authType models.AuthType, success bool, servingNetworkName, udmUrl string) error {
timeNow := time.Now()
timePtr := &timeNow

var authEvent models.AuthEvent
authEvent.TimeStamp = timePtr   //时间戳
authEvent.AuthType = authType   //验证方式
authEvent.Success = success     //认证结果
authEvent.ServingNetworkName = servingNetworkName   //服务网络名称

client := createClientToUdmUeau(udmUrl)
_, _, confirmAuthErr := client.ConfirmAuthApi.ConfirmAuth(context.Background(), id, authEvent)
return confirmAuthErr
}

五、总结

本文借助free5gc+UERANSIM模拟5G网络环境,通过抓包和源码分析的方式介绍了33501标准中的安全相关服务。希望能帮助到对5G知识感兴趣的读者,不足之处请多多指正。

参考资料

  • 沉烽网络安全实验室:《free5gc+UERANSIM模拟5G网络环境搭建及基本使用》

  • 沉烽网络安全实验室:《基于UERANSIM+free5gc 5G模拟环境的5G_AKA协议解析》

  • 张忠琳:【5G核心网】free5GC 注册请求流程源码分析

  • 3GPP TS 23 502

  • 3GPP TS 33.501

# 协议安全 # 网络安全技术 # 5G安全
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录