为什么需要EAP认证

我们在无线网络安全(1)中说过,所谓的“认证”,在802.11i的RSN(或者说,WPA)中有两种方式,一种是802.1x EAP认证,一种是pre-shared-key认证,而pre-shared-key认证直接跳过认证过程,通过“四次握手”(密钥生成与分发)过程,验证APSTA对于PSK的所有权,是一种相互认证。

pre-shared-key认证有一些缺陷。以我们的无线校园网SYSU_SECURE为例,如果采取pre-shared-key认证,那么就会遇到很多问题:

  • 向一个人分发一份pre-shared-key,本意是让一个人使用。但由于密钥生成与分发过程只验证AP和STA对PSK的所有权,如果这个人(A)将PSK送给了另一个人(B),那么B也可以用这个PSK连接校园网。
  • 更新PSK时如何安全地通知全校同学?

实际上,如果范围很大的话,我们很难控制PSK的传播。在802.11i中引入EAP,就是为了解决大规模无线网络的认证问题。

本文要搞清楚的主要问题

  • 什么是EAP?
  • 使用802.1x EAP认证方法如何产生802.11i需要的PMK?
  • 如何搭建一个WPA2-Enterprise或者说使用802.1x EAP认证方法的无线网络?
  • EAP-TLS如何进行双向验证?

对整个802.1x EAP认证架构的简单介绍

EAP这个东西,是古董。在PPP链路大行其道的时代,EAP就出现了。它最初就是为了解决PPP的认证问题而引入的。对它的具体描述,参见rfc3748。EAP叫做“可扩展认证协议”,它只规定了一个壳子,我们可以通过各种方法改造它以适应我们的要求。

而802.1x,是所谓的“基于端口的介质访问控制”ieee标准。什么意思呢?就是说,在客户端没有认证之前,客户端只能通过“被控制的端口”(controlled port)和网络接入点(比如AP、交换机、路由器等等)进行通信。这就说是,在没有认证之前,网络接入点只接受客户端发来的802.1x帧(在以太网里,TYPE字段值为0x888e),其他的一律扔掉。这样一来,客户端虽然在物理上可以和网络接入点进行通信,但是只能进行认证而不能和别的终端进行通信。如果客户端进行了认证,那么,客户端就可以从不被控制的端口(uncontrolled port)通信,简单地来说就是可以上网了。这样一来,802.1x就提供了一种在以太网上进行访问控制的方法。

那么,802.1x和EAP的关系是怎么样的呢?这是一个略复杂的问题。我们说,在以太网上,TYPE字段设置为0x888e就代表上层协议是802.1x。而它上层的协议包,被称为EAPOL(EAP over LAN),也就是EAP在Lan上的实现。它的包格式被802.1x规定如下:

1.PNG

可是令人迷惑的是,EAP协议有自己的包格式:

2.PNG

那么,在以太网或者802.11无线网中,使用的包格式究竟是哪一套呢?

答案很简单,这两套都使用。而且这两套包的层次是不同的。简单地说,802.1x的作用是“访问控制”,EAP的作用是“认证”。我们先按下不表,看看这个认证体系的拓扑架构:

3.PNG

我们发现,在这个架构里,有三个角色:

  • host – 客户
  • Network Access Server – NAS网络接入服务器
  • Authentication Server – 认证服务器

这三个角色的作用和它的名字基本一样。那么,我们发现,在这个体系中,“认证”是委托给认证服务器做的。但认证服务器和客户的通信必须借助NAS的转发。而NAS转发的包,就是EAP包;客户和NAS的通信,是802.1x,或者说是EAPOL包, EAP包被封装在EAPOL包中;NAS和认证服务器的通信,是RADIUS包。实际上,整个协议栈可以如下示意:

4.PNG

实际上,如果仔细看802.1x-2010的话, 当EAPOL包的TYPE字段被设置为0时, 这个包的PacketBody字段就会是一个EAP包:

5.PNG

我们用wireshark抓包也会看到这一点:

6.PNG

为什么说EAP是用来认证的?因为EAP包是客户和认证服务器用来作认证通信的。理解了这一点,让我们暂时放下理论,先搭建一套使用EAP的802.11无线网络吧。

搭建使用EAP的802.11无线网络

根据802.1x认证的构成要件,这里的无线网络至少要由三个部分:

  • suplicant – 客户
  • Access Point – 无线接入点AP
  • Radius Server – Radius 服务器

需要指出的是,这里的AP是“胖AP”,也就是说,它既担任接入点,又担任DHCP Server和Radius client,如果将AP换做所谓的“瘦AP”,那么,这里会有四个部分。

搭建supplicant

现在的各种操作系统都有直接连接EAP方法的无线网的组件,这一步不用自己做什么。

搭建Radius Server

这里我们使用了FreeRadius这个开源的Radius服务器,在ubuntu18.04 LTS上搭建了Radius服务器。

配置步骤如下:

  1. 在终端中输入

     sudo apt-get install freeradius
    
  2. 安装完成后,打开服务器,修改/etc/freeradius/users,添加一个用户,并使用radtest进行测试:

     echo bob Cleartext-Password := "hello" >> /etc/users
     sudo freeradus -X
     radtest bob hello 127.0.0.1 0 testing123
    
  3. 测试成功后,切换到/etc/freeradius/3.0/certs目录,修改client.cnf,填写自己在users中的用户相关信息(比如CN = bob),并使用make工具产生证书:

     vim client.cnf
     make
    
  4. 修改/etc/freeradius/3.0/mods-enabled/eap文件,将ca证书改成刚刚修改好的证书:

     ca_file = /etc/freeradius/3.0/certs/ca.pem
    
  5. 修改/etc/freeradius/3.0/client.conf文件,新建一个clinet,准备与ap连接

     client 192.168.1.1 {
       ipaddr = 192.168.1.1
       proto = *
       secret = testing123
     }
    
  6. 将此服务器和AP连接到同一个网络,这里我使用的是虚拟机,所以新建了一块桥接网卡。

至此,Radius服务器就建好了,下面搭建AP。

搭建AP

这里我们采用了我家的家用路由器。

  • 型号:ASUS RT-AC87R
  • 固件版本:华硕原生固件 3.0.0.4.376_2769-g1bb5fac

配置步骤如下:

  1. 无线网络-一般设置中将2.4G的验证方式设置为WPA-Enterprise。
  2. 无线网络-Radius设置中,填写Radius服务器地址、端口、密码等信息。

至此,AP配置完成。

说明

freeradius是一个很强的服务器,如果搭建到了这里,它的默认设置就几乎可以支持市面上常见的所有EAP方法,包括EAP-MD5、EAP-TLS、EAP-TTLS、EAP-PEAP等。

连接到这个无线网路

使用PEAP方法

在Windows平台和ios平台下,直接连接上面的无线网络,操作系统会默认使用PEAP方法。在GUI中输入用户名和密码即可。

使用EAP-TLS方法

为什么要使用EAP-TLS方法呢?因为PEAP方法会第一阶段会创造tls信道,第二阶段分析起来不太方便。我们对TLS也相当熟悉,所以决定使用EAP-TLS方法进行分析整个连接过程。如果要分析,就必须先连接上。这里使用Windows平台进行连接。

在上一步的配置中,freeradius会产生一堆证书:

7.PNG

将clinet.p12复制一份到windows平台下,双击,进行安装。注意选择“标记为可导出的证书”选项。

8.PNG

然后在控制面版中新建一个无线连接:

填写相关参数,并选择下一步

选择更改连接设置

在这个界面需要更改两个内容:

  1. 高级设置中将指定身份验证模式改为用户身份验证

    14.png

  2. 选择网络身份验证方法中选择Microsoft智能卡或其他证书,并点击设置

    设置页面取消对通过验证证书验证服务器的身份的选择:

然后,在GUI中直接连接。

分析EAP-TLS方法的全过程

在刚才的连接过程中,我们可以看到,整个设置很繁琐。这是因为EAP-TLS使用了Client Certificate来验证客户端的有效性。

Clinet Certificate与tls1.2中的Client Certificate、Certificate Verify帧

rfc5246中,定义了一个我们在TLS系列中没有分析过的帧 – clinet certificate. 这一帧是在收到服务器发来的Certificate Request帧后,客户端必须发送的帧。服务端通过这一帧来验证客户端的的身份。然而,在https的世界里,我们很少使用这个东西。因为http对应的主要是web应用,web应用一般不会要求验证用户的身份,即使真的要求,基于https的身份验证也会让使用http的用户无法登录,还有部署麻烦等劣势,所以用的很少,我们在之前的TLS文章中也没有研究。

这一帧的结构如下:

Client certificates are sent using the Certificate structure defined in Section 7.4.2.

7.4.2是Server Certificate的定义,所以这里也和Server Certificate一样,是直接明文发过去的。

回忆TLS中对于Server Certificate的验证,我们会发现,如果只发送Client Certificate帧,是不能验证客户端对于这个证书的所有权的,验证所有权的关键,应该是私钥。客户端对证书的所有权,是Certificate Verify帧验证的。

这一帧的结构如下:

struct {
    digitally-signed struct
    {
        opaque handshake_messages[handshake_messages_length];
    }
} CertificateVerify;

handshake_messages指的是从握手开始到握手结束的所有消息的连接,而digitally-signed正是指客户端需要用私钥加密这些消息。这样一来,服务端端用证书中的公钥解密,判断一下是否和自己存储/打的哈希一致,就可以验证客户端对证书的所有权了。

EAP-TLS方法如何进行双向认证

  • 客户端认证服务端:通过tls的密钥交换,是标准的tls方法,和一般使用的tls一致。
  • 服务端认证客户端:通过Client Certificate和Certificate Verify消息,是标准的tls方法,但不常用。

EAP-TLS方法的协议栈

既然这个方法名字叫做EAP-TLS,那么就是使用TLS来进行双向认证的。这里有个问题,那就是我们现在无法使用IP协议和TCP协议,如何使用TLS呢?这里采取的方法是,将TLS的帧封装在EAP协议中。

用wireshark抓包,可以很清晰地看出这个情况:

下面我们来分析认证的全过程。

第一阶段 :发送身份信息

首先需要说明,以下所有的通信都是发生于Radius Server(认证服务器)和STA之间的,AP只是起转发作用。

在做完NULL Authentication之后,STA发送EAPOL_Start帧,表明开始进行802.1x认证:

之后,STA回应AP的Request Identity消息,发送自己的身份信息:

如果身份信息合法,进入下一阶段

第二阶段 :协商EAP方法

AP发送Request-MD5-Challenge消息,要求使用EAP-MD5-Challenge方法:

客户端不同意,发送NAK消息,并指出自己想使用EAP-TLS方法:

AP换用EAP-tls方法,发送Request-eap-tls消息:

下面的消息就全部是tls协议帧了。

第三阶段 :EAP-TLS过程

eap-tls由rfc2716定义,现在通行的是rfc5216

成功的eap-tls整个过程大概有三种情况,一种是标准的tls握手过程,另一种是标准的tls快速恢复握手过程,还有一种是支持privacy的两次握手。这里只观察到了第一种,故只讨论第一种。

此过程和一般的tls握手过程主要有以下区别:

  • 服务端发送Certificate Request消息,客户端回应client Certificate 和 Certificate Verify消息。
  • 同时进行EAP-TLS Key Hierarchy过程。注意,这并不是说TLS的Key Hierarchy过程就不进行了,而是说另外地进行其他的Key Hierarchy过程。由于握手过程的最后一帧finished是加密的,所以标准的TLS的Key Hierarchy也是必须的。

抓包结果如下:

第四阶段 :EAP成功/失败

如果成功,AP向STA发送EAP Success消息,如果失败,AP向STA发送EAP Failure消息。

EAP-TLS如何为802.11i的Key Hierarchy过程提供PMK

我们知道,在802.11i无线网络中,Key Hierachy的起点是PMK(Pairwise Master Key)。如果使用PSK方法,那么PMK就是PSK。如果使用EAP方法呢?802.11-2007并没有说得很明白,而是使用了May这样的词,但从“密码”到PSK所使用的哈希函数也是may,所以还是很有参考价值的。它指向了一个很奇怪的记号:MS-MPPE-Recv-Key。这个MS恐怕指的就是Microsoft了,而这个符号实际上来源于PEAP,是PEAP第一阶段(也是用TLS,只不过没有用Cilent Certificate校验客户端)通过Key Hierarchy产生的密钥。

EAP-TLS提供了一种和标准TLS不同的方法,来生成PMK,在rfc-5216的2.3节中被这样定义:

 Key_Material = TLS-PRF-128(master_secret, "client EAP encryption", client.random || server.random)
 MSK = Key_Material(0,63)
 EMSK = Key_Material(64,127)
 IV = TLS-PRF-64("", "client EAP encryption", client.random || server.random)
 Enc-RECV-Key = MSK(0,31) 
    /*
    Peer to Authenticator Encryption Key
    (MS-MPPE-Recv-Key in [RFC2548]). Also known as the
    PMK in [IEEE-802.11].
    */
 Enc-SEND-Key = MSK(32,63) 
    /*
    Authenticator to Peer Encryption Key
    (MS-MPPE-Send-Key in [RFC2548])
    */

为什么MS-MPPE-Recv-Key成了事实上的PMK呢?这似乎有历史原因,我并没有找到一个解释或是说明。但事实就是这样,我们的好奇心也不必过于旺盛。

这时,所有的问题都解决了吗?确实解决了。但是我们又有了新的问题:tls握手是在Authentication Server和Client之间发生的,AP是如何得到Enc-RECV-Key的呢?下一阶段的Key Hierarchy是AP进行的,它必须得到PMK。

我们仔细研究一下Radius Server发给AP的最后一帧:

图中确实看到了MS-MPPE-RECV-KEY字段,但为什么长度不是0x22(32byte的Key, 1byte的Id,1byte的length),而是0x34(52)呢?这是因为它不是明文传的,而是加密+padding后的结果。具体是如何加密的,可以参考rfc2548,此处就不赘述了。

总结

研究EAP是一件不那么轻松的事,主要原因一是资料少,二是资料基本都是英文的,中文搜索几乎没有什么有用结果。通过写这篇文章、研究这些内容,我已经基本搞清楚了802.11i认证过程的所有过程,不过还有很多坑待填,譬如最后产生的GTK究竟有什么用、如何处理漫游等等问题。不过,相信在不远的将来,我会完全研究清楚这些问题。

最后来谈一谈我在部署过程中所踩的坑。

  • 我们必须安装PKCS格式的证书,而不是.crt .pem那样的base64编码的证书(不然私钥无法安装)。
  • 我们必须勾选“允许导出”选项,不然不会使用这张证书。
  • 我们必须设置“用户认证”,不然windows会将我们计算机的主机名在eap identity里传过去。