This is an old revision of the document!



Android and Hotspot 2.0/Passpoint

  • This page will discuss the provisioning of Passpoint credentials to Android devices.
  • The information on this page https://source.android.com/docs/core/connect/wifi-passpoint was used as a reference.
  • Our approach, however will be a bit more hands on by looking at a PHP script that is used to provision a Passpoint profile.

  • 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.

  • The following file demonstrates how we can use PHP to serve the Passpoint configuration file.
PasspointController.php
<?php
 
namespace App\Controller;
use App\Controller\AppController;
use Cake\Http\Response;
 
 
class PasspointController extends AppController{
 
    protected $ca = <<<EOD
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----
EOD;
 
    public function initialize():void{  
        parent::initialize();
        $this->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    = <<<EOD
<MgmtTree xmlns="syncml:dmddf1.2">
  <VerDTD>1.2</VerDTD>
  <Node>
    <NodeName>PerProviderSubscription</NodeName>
    <RTProperties>
      <Type>
        <DDFName>urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0</DDFName>
      </Type>
    </RTProperties>
    <Node>
      <NodeName>i001</NodeName>
      <Node>
        <NodeName>HomeSP</NodeName>
        <Node>
          <NodeName>FriendlyName</NodeName>
          <Value>WiFi-K9.5Jun24</Value>
        </Node>
        <Node>
          <NodeName>FQDN</NodeName>
          <Value>mesh-manager.com</Value>
        </Node>
      </Node>
      <Node>
        <NodeName>Credential</NodeName>
        <Node>
          <NodeName>Realm</NodeName>
          <Value>mesh-manager.com</Value>
        </Node>
        <Node>
          <NodeName>UsernamePassword</NodeName>
          <Node>
            <NodeName>Username</NodeName>
            <Value>ppsk_demo@ppsk_demo</Value>
          </Node>
          <Node>
            <NodeName>Password</NodeName>
            <Value>dGVzdGluZzEyMw==</Value>
          </Node>
          <Node>
            <NodeName>EAPMethod</NodeName>
            <Node>
              <NodeName>EAPType</NodeName>
              <Value>21</Value>
            </Node>
            <Node>
              <NodeName>InnerMethod</NodeName>
              <Value>MS-CHAP-V2</Value>
            </Node>
          </Node>
        </Node>
      </Node>
    </Node>
  </Node>
</MgmtTree> 
EOD;  
        $home_sp_64 = base64_encode($home_sp);  
        $ca_64      = base64_encode($this->ca);             
        $home_sp_ca = <<<EOD
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="XXXXboundary"
Content-Transfer-Encoding: base64
 
--XXXXboundary
Content-Type: application/x-x509-ca-cert
Content-Transfer-Encoding: base64
 
$ca_64
 
--XXXXboundary
Content-Type: application/x-passpoint-profile
Content-Transfer-Encoding: base64
 
$home_sp_64
 
--XXXXboundary--
EOD;       
 
        $response = $response->withStringBody(base64_encode($home_sp_ca));
        return $response;
    }
}

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 = <<<EOD
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
EOD;
  • It will be also base64 encrypted 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    = <<<EOD
<MgmtTree xmlns="syncml:dmddf1.2">
  <VerDTD>1.2</VerDTD>
  <Node>
 ..... 
  </Node>
</MgmtTree> 
EOD;  
  • It will be also base64 encrypted before it is combined with the other elements
$home_sp_64 = base64_encode($home_sp); 

Combining and sending

  • These two base64 encrypted strings is then in turn combined and base64 encrypted one last time before it is served by the web server.
  • Here we combine it:
$home_sp_ca = <<<EOD
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="XXXXboundary"
Content-Transfer-Encoding: base64
 
--XXXXboundary
Content-Type: application/x-x509-ca-cert
Content-Transfer-Encoding: base64
 
$ca_64
 
--XXXXboundary
Content-Type: application/x-passpoint-profile
Content-Transfer-Encoding: base64
 
$home_sp_64
 
--XXXXboundary--
EOD;       
  • 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:
  1. Content has to be served from a web server with FQDN and HTTPS.
  2. Content has to be served with specified header settings.
  3. Content has to be base64 encoded.
  4. Content contains.
    1. Base64 encoded CA Certificate.
    2. Base64 encoded MgmtTree XML.
  5. These two are combined and base64 encoded as per step3.

  • 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.
  • 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.
  • technical/pp-android.1751776468.txt.gz
  • Last modified: 2025/07/06 06:34
  • by system