-----
====== 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.2PerProviderSubscriptionurn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0i001HomeSPFriendlyNameRADIUSdesk-HS2.0 07-Jul-25FQDNmesh-manager.comCredentialRealmmesh-manager.comUsernamePasswordUsernameppsk_demo@ppsk_demoPassworddGVzdGluZzEyMw==EAPMethodEAPType21InnerMethodMS-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.
ExtensionAndroidAAAServerTrustedNamesFQDNradiusdesk.com;openwrt.org
* This section has to be on the same level as **HomeSP** and **Credential**.