Passed
Push — master ( 23a6d3...f7b675 )
by Stefan
07:04
created

DevicePPOSUXML::aaaServerTrustRoot()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 16
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
/*
4
 * ******************************************************************************
5
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
6
 * and GN4-2 consortia
7
 *
8
 * License: see the web/copyright.php file in the file structure
9
 * ******************************************************************************
10
 */
11
12
/**
13
 * This file contains the TestModule class
14
 *
15
 * This is a very basic example of using the CAT API.  
16
 *
17
 * The module contains two files
18
 * in the Files directory. They will illustrate the use of the {@link DeviceConfig::copyFile()} method.
19
 * One fille will be coppied without the name change, for the second we will provide a new name.
20
 * The API also contains a similar {@link DeviceConfig::translateFile()} method, which is special to Windows installers and not used in this example.
21
 *
22
 * This module will collect all certificate files stored in the database for a given profile and will copy them to the working directory.
23
 *
24
 * If, for the given profile, an information file is available, this will also be copied to the working directory.
25
 *
26
 * The installer will collect all available configuration attributes and save them to a file in the form of the PHP print_r output.
27
 *
28
 * Finally, the installer will create a zip archive containing all above files and this file 
29
 * will be sent to the user as the configurator file.
30
 *
31
 * Go to the {@link DeviceTestModule} and {@link DeviceConfig} class definitions to learn more.
32
 *  
33
 * @package ModuleWriting
34
 */
35
36
namespace devices\PP_OSU_XML;
37
38
use Exception;
39
40
/**
41
 * This is the main implementation class of the module
42
 *
43
 * The name of the class must the the 'Device' followed by the name of the module file
44
 * (without the '.php' extension), so in this case the file is "TestModule.php" and
45
 * the class is DeviceTestModule.
46
 *
47
 * The class MUST define the constructor method and one additional 
48
 * public method: {@link writeInstaller()}.
49
 *
50
 * All other methods and properties should be private. This example sets zipInstaller method to protected, so that it can be seen in the documentation.
51
 *
52
 * It is important to understand how the device module fits into the whole picture, so here is s short descrption.
53
 * An external caller (for instance {@link GUI::generateInstaller()}) creates the module device instance and prepares
54
 * its environment for a given user profile by calling {@link DeviceConfig::setup()} method.
55
 *      this will:
56
 *       - create the temporary directory and save its path as $this->FPATH
57
 *       - process the CA certificates and store results in $this->attributes['internal:CAs'][0]
58
 *            $this->attributes['internal:CAs'][0] is an array of processed CA certificates
59
 *            a processed certifincate is an array 
60
 *               'pem' points to pem feromat certificate
61
 *               'der' points to der format certificate
62
 *               'md5' points to md5 fingerprint
63
 *               'sha1' points to sha1 fingerprint
64
 *               'name' points to the certificate subject
65
 *               'root' can be 1 for self-signed certificate or 0 otherwise
66
 *       - save the info_file (if exists) and put the name in $this->attributes['internal:info_file_name'][0]
67
 * Finally, the module {@link DeviceConfig::writeInstaller ()} is called and the returned path name is used for user download.
68
 *
69
 * @package ModuleWriting
70
 */
71
class DevicePPOSUXML extends \core\DeviceConfig {
72
73
    /**
74
     * Constructs a Device object.
75
     *
76
     * @final not to be redefined
77
     */
78
    final public function __construct() {
79
        parent::__construct();
80
        $this->setSupportedEapMethods([\core\common\EAP::EAPTYPE_SILVERBULLET]);
81
    }
82
    
83
    private function aaaServerTrustRoot() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
Unused Code introduced by
The method aaaServerTrustRoot() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
84
        
85
      $retval = '<Node>
86
        <NodeName>AAAServerTrustRoot</NodeName>';
87
      foreach ($this->attributes['internal:CAs'][0] as $oneCert) {
88
          $retval .= '<Node>
89
                         <NodeName>'.$oneCert['uuid'].'</NodeName>
90
                             <Node>
91
                               <NodeName>CertSHA256Fingerprint</NodeName>
92
                               <Value>'.$oneCert['sha256'].'</Value>
93
                             </Node>
94
                       </Node>
95
                  ';
96
      }
97
      $retval .= '</Node>';
98
      return $retval;
99
    }
100
    
101
    private function credentialCreationDate() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
Unused Code introduced by
The method credentialCreationDate() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
102
        $now = new \DateTime();
103
        return '<Node>
104
          <NodeName>CreationDate</NodeName>
105
          <Value>'.$now->format("Y-m-d") . "T" . $now->format("H:i:s") . "Z".'</Value>
106
        </Node>';
107
    }
108
    
109
    private function homeSP() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
110
        $retval = '<Node>
111
        <NodeName>HomeSP</NodeName>
112
        <Node>
113
          <NodeName>FriendlyName</NodeName>
114
          <Value>'.sprintf(_("%s via Passpoint"),\config\ConfAssistant::CONSORTIUM['display_name']).'</Value>
115
        </Node>
116
        <Node>
117
          <NodeName>FQDN</NodeName>
118
          <Value>'.$this->attributes['eap:server_name'][0] /* what, only one FQDN allowed? */.'</Value>
119
        </Node>
120
        <Node>
121
          <NodeName>RoamingConsortiumOI</NodeName>
122
          <Value>';
123
        $oiList = "";
124
        $numberOfOi = count(\config\ConfAssistant::CONSORTIUM['interworking-consortium-oi']);
125
        foreach (\config\ConfAssistant::CONSORTIUM['interworking-consortium-oi'] as $index => $oneOi) {
126
            // according to spec, must be lowercase ASCII without dashes
127
            // but sample I got was all uppercase, so let's try with that
128
            $oiList .= str_replace("-","",trim(strtoupper($oneOi)));
129
            if ($index < $numberOfOi - 1) {
130
                // according to spec, comma-separated
131
                $oiList .= ",";
132
            }
133
        }
134
        $retval .= $oiList.'</Value>
135
        </Node>
136
      </Node>';
137
        return $retval;
138
    }
139
    
140
    private function credential() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
141
        $retval = '<Node>
142
        <NodeName>Credential</NodeName>';
143
        /* the example file I got did not include CreationDate, so omit it
144
         * 
145
         * $content .= $this->credentialCreationDate();
146
         */
147
        $retval .= '
148
          <Node>
149
            <NodeName>DigitalCertificate</NodeName>
150
            <Node>
151
              <NodeName>Realm</NodeName>
152
              <Value>'.$this->attributes['internal:realm'][0].'</Value>
153
            </Node>
154
            <Node>
155
              <NodeName>CertificateType</NodeName>
156
              <Value>x509v3</Value>
157
            </Node>
158
            <Node>
159
              <NodeName>CertSHA256Fingerprint</NodeName>
160
              <Value>'.strtoupper($this->clientCert["sha256"]) /* the actual cert has to go... where? */.'</Value>
161
            </Node>
162
          </Node>
163
      </Node>';
164
        return $retval;
165
    }
166
    
167
    private function perProviderSubscription() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
168
        $retval = '<MgmtTree xmlns="syncml:dmddf1.2">
169
  <VerDTD>1.2</VerDTD>
170
  <Node>
171
    <NodeName>PerProviderSubscription</NodeName>
172
    <RTProperties>
173
      <Type>
174
        <DDFName>urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0</DDFName>
175
      </Type>
176
    </RTProperties>
177
    <Node>
178
      <NodeName>CATPasspointSetting</NodeName>';
179
        /* it seems that Android does NOT want the AAAServerTrustRoot section
180
           and instead always validates against the MIME cert attached
181
182
      $content .= $this->aaaServerTrustRoot();
183
         */
184
      $retval .= $this->homeSP();
185
      $retval .= $this->credential();
186
      
187
    $retval .= '</Node>
188
  </Node>
189
</MgmtTree>';
190
    return $retval;
191
    }
192
    /**
193
     * prepare the PPS-MO file with cert MIME attachments
194
     *
195
     * @return string installer path name
196
     */
197
    public function writeInstaller() {
198
        $this->loggerInstance->debug(4, "HS20 PerProviderSubscription Managed Object Installer start\n");
199
        
200
        $content_encoded = chunk_split(base64_encode($this->perProviderSubscription()), 76, "\n");
201
        // sigh... we need to construct a MIME envelope for the payload and the cert data
202
        $content_encoded = 'Content-Type: multipart/mixed; boundary={boundary}
203
Content-Transfer-Encoding: base64
204
205
--{boundary}
206
Content-Type: application/x-passpoint-profile
207
Content-Transfer-Encoding: base64
208
209
'.$content_encoded.'--{boundary}';
210
        // then, another MIME body for each CA certificate we referenced earlier
211
        // only leaves me to wonder what the "URL" for those is...
212
        foreach ($this->attributes['internal:CAs'][0] as $oneCert) {
213
            $content_encoded .= '
214
Content-Type: application/x-x509-ca-cert
215
Content-Transfer-Encoding: base64
216
217
'.chunk_split(base64_encode($oneCert['pem']), 76, "\n").
218
'--{boundary}';
219
            
220
        }
221
        // and our own client cert - what about intermediates?
222
        $content_encoded .= '
223
Content-Type: application/x-pkcs12
224
Content-Transfer-Encoding: base64
225
226
'.chunk_split(base64_encode($this->clientCert['certdataclear']), 76, "\n"). // is PKCS#12, with cleartext key
227
'--{boundary}';
228
229
        // trail this with a double slash and a newline
230
        $content_encoded .= "--\n";
231
        // strangely enough, now encode ALL OF THIS in base64 again. Whatever.
232
        file_put_contents('installer_profile', chunk_split(base64_encode($content_encoded), 76, "\n"));
233
234
        // $fileName = $this->installerBasename . '.bin';
235
        $fileName = "passpoint.config";
236
237
        if (!$this->sign) {
238
            rename("installer_profile", $fileName);
239
            return $fileName;
240
        }
241
242
        // still here? We are signing. That actually can't be - the spec doesn't
243
        // foresee signing.
244
        // but if they ever change their mind, we are prepared
245
246
        $outputFromSigning = system($this->sign . " installer_profile '$fileName' > /dev/null");
247
        if ($outputFromSigning === FALSE) {
248
            $this->loggerInstance->debug(2, "Signing the ONC installer $fileName FAILED!\n");
249
        }
250
251
        return $fileName;
252
    }
253
254
    /**
255
     * prepare module desctiption and usage information
256
     * 
257
     * @return string HTML text to be displayed in the information window
258
     */
259
    public function writeDeviceInfo() {
260
        $out = "<p>";
261
        $out .= _("This installer is an example only. It produces a zip file containig the IdP certificates, info and logo files (if such have been defined by the IdP administrator) and a dump of all available attributes.");
262
        return $out;
263
    }
264
265
}
266