运营商 Wi-Fi

运营商 Wi-Fi 是一种自动连接功能(使用加密的 IMSI),在 Android 9 及更高版本中可用,允许设备自动连接到运营商实施的 Wi-Fi 网络。在高拥堵区域或蜂窝网络覆盖率极低的区域(例如体育场或地下火车站),运营商 Wi-Fi 可用于改善用户的连接体验并分流流量。

具有运营商 Wi-Fi 功能的设备会自动连接到配置的运营商 Wi-Fi 网络(具有公钥证书的网络)。当用户手动断开与运营商 Wi-Fi 网络的连接时,该网络将被列入黑名单 24 小时(无自动连接)。用户可以随时手动连接到已列入黑名单的网络。

实现

设备制造商和运营商必须执行以下操作才能实施运营商 Wi-Fi。

制造商

对于运行 Android 11 及更高版本的设备,请使用 Wi-Fi 建议 API 为每个运营商添加 Wi-Fi 配置文件。

对于运行 Android 10 或更低版本的设备,请通过在运营商配置管理器中为每个运营商配置 carrier_wifi_string_array 参数来添加 Wi-Fi 配置文件。

  • carrier_wifi_string_array:一个字符串数组,其中每个字符串条目是以逗号分隔的 Base64 编码的 Wi-Fi SSID 和 EAP 类型,其中 EAP 类型是一个整数(请参阅可扩展身份验证协议 (EAP) 注册表)。例如,以下配置适用于使用 EAP-AKASOME_SSID_NAME 和使用 EAP-SIMSome_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 的 URL,该公钥用于 IMSI 加密。例如,以下配置提供了一个特定的 URL

    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:一个标志,指示是否允许通过按流量计费的网络(蜂窝网络)下载运营商的公钥。如果未设置此标志,则没有 Wi-Fi 连接的新设备将无法连接到运营商 Wi-Fi 网络,因为它将不允许下载密钥。

    config {
      key: "allow_metered_network_for_cert_download_bool"
      bool_value: true
    }
    

运营商

要实施运营商 Wi-Fi,运营商必须启用 IMSI 隐私保护并提供公钥。

IMSI 隐私保护

Android 使用公钥加密技术保护订阅者永久身份 (IMSI) 的机密性。Android 实施了无线宽带联盟 (WBA) 关于 Wi-Fi IMSI 隐私保护的规范。当连接启用 IMSI 隐私保护时,永久订阅者身份不会在空中以明文形式传输。

永久身份加密

加密的永久身份的格式如下

  • 永久身份的格式为 <EAP-Method><IMSI>@<NAI realm>
  • EAP-Method 前缀是一个单字节,用于定义用于身份验证的 EAP 方法
    • 0:EAP-AKA
    • 1:EAP-SIM
    • 6: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-AKA
  • 1:EAP-SIM
  • 6: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-AKA
  • 1:EAP-SIM
  • 6:EAP-AKA'

密钥标识符属性值对是可选的,如果未使用,则不会附加到加密的永久身份的末尾。

此时,服务器从密钥标识符(如果提供)中找到私钥,使用运营商私钥解密加密的身份,并继续正常的 EAP 流程。

身份验证成功后,服务器可以提供快速重新身份验证身份或临时身份(假名),该身份用于后续连接。如果服务器未提供临时身份,则系统会在后续连接中发送加密的身份。

运营商证书检索、过期和吊销

如果系统中未安装证书,则系统使用 imsi_key_download_url_string 运营商配置中提供的 URL,使用 HTTP GET 方法下载证书。仅当 allow_metered_network_for_cert_download_bool 运营商配置设置为 true 时,系统才使用蜂窝数据。否则,系统仅在 Wi-Fi 连接可用时下载证书。

证书过期由系统强制执行。系统会在证书到期日期前 21 天开始尝试续订证书,并使用相同的 URL 下载新证书。

如果服务器无法解密加密的身份,则服务器会发送 EAP-Request/AKA-Notification 消息,其中 AT_NOTIFICATION 代码为 General Failure (16384),以终止 EAP 交换。

如果证书被吊销或过期,则服务器会发送 EAP-Request/AKA-Notification 消息,其中 AT_NOTIFICATION 代码为 Certificate Replacement Required (16385),以终止 EAP 交换。作为响应,系统会应用内部启发式方法来确定是否删除证书并尝试从同一 URL 下载新证书。

提供公钥

提供指向服务器的公共 URL,最好使用基于 TLS 的 HTTP,该服务器托管运营商的证书,其中

  1. 公钥和到期日期可以从证书中提取。
  2. 来自服务器的信息采用以下 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-----"
    } ]
    }