运营商 Wi-Fi 是 Android 9 及更高版本中提供的一项自动连接功能(使用加密的 IMSI),该功能可让设备自动连接到运营商实现的 Wi-Fi 网络。在网络极为拥挤或手机信号覆盖范围很小的区域,如体育场或地铁站,运营商 Wi-Fi 功能可用于改善用户的连接体验并起到分载流量的作用。
具有运营商 WLAN 功能的设备会自动连接到已配置的运营商 WLAN 网络(具有公钥证书的网络)。当用户手动断开与运营商 WLAN 网络的连接时,该网络将被列入黑名单 24 小时(不会自动连接)。用户可以随时手动连接到已列入屏蔽名单的网络。
在搭载 Android 9 或更高版本且已实现运营商 WLAN 功能的设备上,默认不会通过运营商 WLAN 功能自动连接网络。当设备首次尝试连接到运营商 WLAN 网络时,用户会收到通知。
实现
如需实现运营商 WLAN 功能,设备制造商和运营商必须执行以下操作。
制造商
对于搭载 Android 11 及更高版本的设备,请使用 Wi-Fi suggestion API 为每个运营商添加 WLAN 配置文件。
对于搭载 Android 10 或更低版本的设备,请通过在运营商配置管理器中为每个运营商配置 carrier_wifi_string_array
参数来添加 WLAN 配置文件。
carrier_wifi_string_array
:一个字符串数组,其中各字符串条目是一个以 Base64 编码的 Wi-Fi SSID 和一个 EAP 类型,二者以英文逗号隔开,并且 EAP 类型是一个整数(请参阅可扩展身份验证协议 (EAP) 注册表)。例如,以下配置针对使用 EAP-AKA 的 SOME_SSID_NAME 和使用 EAP-SIM 的 Some_Other_SSID:config { key: "carrier_wifi_string_array" text_array { item: "U09NRV9TU0lEX05BTUUK,23" item: "U29tZV9PdGhlcl9TU0lECg==,18" } }
在运营商配置管理器中,为每个运营商配置以下参数:
imsi_key_availability_int
:标识用于 IMSI 加密的密钥是适用于 WLAN(设置位 1)还是 EPDG(设置位 0),或两者都适用(同时设置位 0 和位 1)。例如,以下配置表示 IMSI 加密适用于 WLAN,但不适用于 EPDG:config { key: "imsi_key_availability_int" int_value: 2 }
imsi_key_download_url_string
:从中下载 proto 文件(包含用于 IMSI 加密的运营商公钥)的网址。例如,以下配置提供了特定的网址:config { key: "imsi_key_download_url_string" text_value: "https://www.some_company_name.com:5555/some_directory_name/some_filename.json" }
allow_metered_network_for_cert_download_bool
:一个标记,表明是否允许通过按流量计费的(移动)网络下载运营商公钥。如果未设置此标记,没有 WLAN 连接的新设备将会因为无法下载密钥而不能连接到运营商 WLAN 网络。config { key: "allow_metered_network_for_cert_download_bool" bool_value: true }
运营商
如需实现运营商 WLAN 功能,运营商必须启用 IMSI 隐私保护并提供一个公钥。
IMSI 隐私保护
Android 使用公钥加密技术保护用户永久识别码 (IMSI) 的安全。Android 实现了针对适用于 Wi-Fi 的 IMSI 隐私保护的无线宽带联盟 (WBA) 规范。为网络连接启用 IMSI 隐私保护后,用户永久识别码不会通过无线下载的方式以明文传输。
永久识别码加密
经过加密的永久识别码格式如下:
- 永久识别码采用
<EAP-Method><IMSI>@<NAI realm>
格式。 - EAP-Method 前缀是一个八位字节,用于定义在身份验证时使用的 EAP 方法:
0
:EAP-AKA1
:EAP-SIM6
:EAP-AKA'
- NAI Realm 格式为
wlan.mncXXX.mccYYY.3gppnetwork.org
,其中XXX
将替换为 SIM 卡的移动网络代码 (MNC),YYY
将替换为移动设备国家/地区代码 (MCC)。 - 永久识别码使用运营商提供的 RSA 公钥进行加密。该公钥包含在 X.509 证书中。
- 加密方案为 RSAES-OAEP,并使用 SHA-256 作为加密哈希函数。该加密方案在每次使用时都能确保密文的唯一性,从而避免生成一个可能被追踪的固定识别码。
- RSA 密钥长度为 2048 位。
- 加密缓冲区为 256 个字节。
- 密文使用 Base64 编码。
- 输出的已加密永久识别码的长度为 344 个字节。
Encrypted Permanent Identity = Base64(RSAES-OAEP-SHA-256(<EAP-Method><IMSI>@<NAI Realm>))
密钥标识符
密钥标识符是运营商附加到证书的可选属性值对,可让服务器在身份验证期间找到正确的私钥。密钥标识符的示例:CertificateSerialNumber=123456
。如果提供了密钥标识符,则会在身份验证过程中以明文形式发送相应的密钥标识符。
对基于 SIM 卡的 EAP 身份验证方法的修改
如果对某个网络连接启用 IMSI 隐私保护,那么系统在收到 EAP-Request/Identity
时并不会发送永久识别码,而是使用匿名登录进行响应:
SERVER: EAP-Request/Identity
UE: EAP-Response/Identity AT_IDENTITY=<prefix>|anonymous@<NAI Realm>
<prefix>
是可选项。如果 enable_eap_method_prefix_bool
运营商配置设为 true
,识别码的第一个字符(anonymous
前面的字符)会在 EAP 交换开始之前将所用的 EAP 方法类型告知服务器。
0
:EAP-AKA1
:EAP-SIM6
:EAP-AKA'
如果运营商配置设为 false
,该前缀将不会包含在相应消息中。
在响应中,服务器会发送 EAP-Request/AKA-Identity
消息,然后系统会采用以下格式进行响应:
SERVER: EAP-Request/AKA-Identity AT_ANY_ID_REQ
UE: EAP-Response/AKA-Identity AT_IDENTITY=<prefix>|<Encrypted Permanent Identity>|","|"<attribute>=<value>"
识别码的第一个字符会告知服务器使用了经过加密的识别码,或提供配置的 EAP 方法类型:
\0
:经过加密的永久识别码0
:EAP-AKA1
:EAP-SIM6
:EAP-AKA'
密钥标识符属性值对是可选的,如果未使用,则不会附加到已加密永久识别码的末尾。
此时,服务器会从密钥标识符(如已提供)中找到相应私钥,使用运营商私钥解密经过加密的识别码,然后继续完成正常的 EAP 流程。
成功进行身份验证后,服务器会提供可快速重新验证的识别码或临时识别码(非真实识别码),以用于后续连接。如果服务器未提供临时识别码,系统会在后续连接中发送已加密识别码。
运营商证书检索、失效和撤消
如果系统中未安装任何证书,系统会使用 imsi_key_download_url_string
运营商配置中提供的网址通过 HTTP get 方法下载证书。仅当 allow_metered_network_for_cert_download_bool
运营商配置设为 true
时,系统才会使用移动数据网络。否则,系统只会在有可用的 Wi-Fi 连接时下载证书。
证书失效由系统强制执行。系统会在证书失效日期前 21 天开始尝试对证书进行更新,并使用同一网址下载新证书。
如果服务器无法解密已加密的识别码,服务器会发送一条包含 AT_NOTIFICATION
代码 General Failure
(16384) 的 EAP-Request/AKA-Notification
消息以终止 EAP 交换。
如果证书被撤消或过期,服务器会发送一条包含 AT_NOTIFICATION
代码 Certificate Replacement Required
(16385) 的 EAP-Request/AKA-Notification
消息以终止 EAP 交换。作为响应,系统会应用内部启发法来确定是否移除相应证书并尝试从同一网址下载新证书。
提供公钥
提供服务器的公开网址,最好使用 HTTP over TLS 来托管运营商证书,其中:
- 公钥和失效日期可从证书中提取。
来自服务器的信息采用 JSON 格式,如下所示:
Property: key-identifier Type: String Encoding: UTF-8 Description: Specifies an identifier that the carrier would like to attach to the certificate. Optional: Yes Property: certificate Property alternative name: public-key Type: String Encoding: Base64 Description: The content of the carrier's X.509 certificate. Optional: No Property: key-type Type: String Encoding: UTF-8 Description: Specifies the module that will use the key. The value for type must be either WLAN or EPDG. Optional: Yes. If the key-type property isn't included, then its value defaults to WLAN.
以下是公钥的示例。
{ "carrier-keys" : [ { "key-identifier" : "CertificateSerialNumber=5xxe06d4", "public-key" : "-----BEGIN CERTIFICATE-----\r\nTIIDRTCCAi2gAwIBAgIEVR4G1DANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJVUzELMAkGA1UE\r\nCBMCTkExCzAJBgNVBAcTAk5BMQswCQYDVQQKEwJOQTELMAkGA1UECxMCTkExEDAOBgNVBAMTB1Rl\r\nc3RiT6N1/w==\r\n-----END CERTIFICATE-----" } ] }