----- ====== Android and Hotspot 2.0/Passpoint ====== ===== Introduction ===== * This page will discuss the provisioning of Passpoint credentials to Android devices. * Information from the following URL was used as a reference: https://source.android.com/docs/core/connect/wifi-passpoint * Our approach, however will be a bit more hands on by looking at a PHP script that is used to provision a Passpoint profile. ------ ===== Provision a Passpoint configuration file ===== * A Passpoint configuration file has to be provisioned through a **web server** that has a valid **SSL certificate** over **HTTPS**. * If you look at the contents of the Passpoint configuration file it probably does not make much sense. * It will be one long line of characters. * This is because the file has to be served as base64 encoded content. * Base64 encoding is a binary-to-text encoding scheme that represents binary data in an ASCII string format. * It's primarily used to transmit binary data over channels that are designed to handle text-based data, such as email or HTTP. * Essentially, it converts binary data into a string of printable characters (A-Z, a-z, 0-9, +, /) that are safe to transmit * This is the general definition of base64 encoding. * In our case, however, we are **NOT** transmitting binary data but rather **other base64 encoded elements**. -------- ===== Simple CakePHP Controller ===== * The following file demonstrates how we can use PHP to serve the Passpoint configuration file. Authentication->allowUnauthenticated([ 'androidProfile']); } public function androidProfile(){ $response = $this->response; $response = $response->withHeader('Content-Transfer-Encoding', 'base64'); $response = $response->withType('application/x-wifi-config'); $home_sp = << 1.2 PerProviderSubscription urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0 i001 HomeSP FriendlyName RADIUSdesk-HS2.0 07-Jul-25 FQDN mesh-manager.com Credential Realm mesh-manager.com UsernamePassword Username ppsk_demo@ppsk_demo Password dGVzdGluZzEyMw== EAPMethod EAPType 21 InnerMethod MS-CHAP-V2 EOD; $home_sp_64 = base64_encode($home_sp); $ca_64 = base64_encode($this->ca); $home_sp_ca = <<withStringBody(base64_encode($home_sp_ca)); return $response; } } ==== Looking at the PHP File and what it does ==== === Sets HTTP headers === * This is so that an Android device knows the content it is about to receive can potentially be a Passpoint profile. $response = $response->withHeader('Content-Transfer-Encoding', 'base64'); $response = $response->withType('application/x-wifi-config'); * There are two items embedded. * The one is the CA Certificate * The other is a MgmtTree XML block which is the actual Passpoint profile definition === Embedded CA Certificate === * The CA have to be included. protected $ca = << * It will be also base64 encoded before it is combined with the other elements $ca_64 = base64_encode($this->ca); === Embedded MgmtTree XML bloc === * The MgmtTree XML bloc is defined here: $home_sp = << 1.2 ..... EOD; * It will be also base64 encoded before it is combined with the other elements $home_sp_64 = base64_encode($home_sp); === Combining and sending === * These two base64 encoded strings is then in turn combined and base64 eencoded one last time before it is served by the web server. * Here we combine it: $home_sp_ca = << * Here we serve it: $response = $response->withStringBody(base64_encode($home_sp_ca)); return $response; * Before we discuss the MgmtTree XML in more detail here is a short overview of the main points: - Content has to be served from a web server with FQDN and HTTPS. - Content has to be served with specified header settings. - Content has to be base64 encoded. - Content contains. - Base64 encoded CA Certificate. - Base64 encoded MgmtTree XML. - These two are combined and base64 encoded as per step3. ----------- ===== MgmtTree XML ===== * The MgmtTree XML can be divided in two parts and when you do this it becomes much simpler to understand. * The one part is the **HomeSP**. * The other part is the **Credential**. * There is also an optional third part called **Extension** which we also cover later. * The **HomeSP** part is used by the Android to discover Hotspot 2.0 / Passpoint WiFi Access Points to connect to. * When such an Access Point is found, the **Credential** part is used to try and authenticate the user. * The **HomeSP** for all practical intend replaces the step where you would typically select or specify an SSID to connect to. * There is one item however that "bleeds" from the **HomeSP** section to the **Credential** section and it can cause the authentication to fail. We will also cover this in detail on this page and what to do to fix things. ------------ ==== HomeSP ==== * HomeSP **have to contain** the following nodes: * **FriendlyName** Displayed by the Android installer and also when connected to the Hotspot 2.0 / Passpoint Access Point. * **FQDN** This translates to the value of Domain and or NAI Realm in Hostapd / OpenWrt. (This is the part that you have to be careful with) * HomeSP **can contain** the following node: * **RoamingConsortiumOI** This is the RCOI and one can specify multiple values separated by commas. ------------- === Credential === * The credential section are mostly straight forward. * There are however some items to highlight. === Realm === * This Realm is used in EAP authentication and is RADIUS related. * This realm has nothing to do with the NAI Realm (or Domain) in Hotspot 2.0. (HomeSP Section) * It might be the same value of the NAI Realm but it is not a requirement. * When the authentication request to RADIUS starts, an anonymous identity is used. * This is also referred to as the **Outer Identity**. * The convention Android uses is to formulate a username anonymouns@. * In this case it will be anonymous@mesh-manager.com. * The EAP protocol uses this recommended convention in order to determine the destination of RADIUS proxy requests. === Password === * The value of the password is also base64 encoded. * Remember that encoded does not equal to encrypted. * It is thus very easy to get the cleartext value of the password: echo "dGVzdGluZzEyMw==" | base64 -d * The get the base64 value of the password in turn you can use echo **with the -n switch**. echo -n "testing123" | base64 === EAPType === * EAPType will in most cases be 21. * This is the number that is assigned for EAP/TTLS and part of the **UsernamePassword** detail. * With this you also have to specify the **InnerMethod** to use when you are authenticating and can be one of the following. * PAP * CHAP * MS-CHAP * or MS-CHAP-V2 * The popular ones are MS-CHAP-V2 and PAP. * When the RADIUS server uses Active Directory, it is the best to choose MS-CHAP-V2 in order to avoid compatibility issues. === Other Credential Options === * There are other credential options which is good to take note of although they beyond the scope of this discussion. * **SIM Authentication**. This will typically require collaboration with a mobile company to validate the incoming RADIUS request against their database for authentication. * **DigitalCertificate Authentication**. This require PKI infrastructure and the management of the client certificates. ------------- ===== Extension - Certificate FQDN Check (Domain Suffix Match) ===== * In WPA Supplicant we have the following option: domain_suffix_match * If this is specified then wpa_supplicant will make sure that when the client authenticates to RADIUS that the domain name of the certificate used with EAP matches one of the specified values. * If not it will reject the authentication. * This is to protect against an Evil Twin scenario. * With the Android Hotspot 2.0 setup it will take the value of FQDN under the HomeSP section as the value value for domain_suffix_match. * This is not always the case in real life. Sometimes the certificate RADIUS used has another domain/FQDN. * If you want to specify a different domain there is an **Extension** section. Extension Android AAAServerTrustedNames FQDN radiusdesk.com;openwrt.org * This section has to be on the same level as **HomeSP** and **Credential**.