1
1
package com .afwsamples .testdpc .policy .wifimanagement ;
2
2
3
+ import static com .afwsamples .testdpc .common .Util .SDK_INT ;
4
+
3
5
import android .app .Activity ;
4
6
import android .app .AlertDialog ;
5
7
import android .app .Dialog ;
6
8
import android .app .DialogFragment ;
9
+ import android .app .admin .DevicePolicyManager ;
7
10
import android .content .ActivityNotFoundException ;
8
11
import android .content .DialogInterface ;
9
12
import android .content .Intent ;
10
13
import android .database .Cursor ;
11
14
import android .net .Uri ;
12
15
import android .net .wifi .WifiConfiguration ;
13
16
import android .net .wifi .WifiEnterpriseConfig ;
17
+ import android .os .Build .VERSION_CODES ;
14
18
import android .os .Bundle ;
15
19
import android .provider .MediaStore ;
20
+ import android .security .KeyChain ;
21
+ import android .security .KeyChainAliasCallback ;
16
22
import android .text .TextUtils ;
17
23
import android .util .Log ;
18
24
import android .view .LayoutInflater ;
19
25
import android .view .View ;
26
+ import android .widget .Button ;
20
27
import android .widget .EditText ;
21
28
import android .widget .TextView ;
22
29
import android .widget .Toast ;
28
35
import java .io .InputStream ;
29
36
import java .security .KeyStoreException ;
30
37
import java .security .NoSuchAlgorithmException ;
31
- import java .security .PrivateKey ;
32
38
import java .security .UnrecoverableKeyException ;
33
39
import java .security .cert .CertificateException ;
34
40
import java .security .cert .CertificateFactory ;
@@ -45,9 +51,12 @@ public class WifiEapTlsCreateDialogFragment extends DialogFragment {
45
51
private final static String ARG_CONFIG = "config" ;
46
52
private static final String TAG = "wifi_eap_tls" ;
47
53
54
+ private DevicePolicyManager mDpm ;
55
+
48
56
private WifiConfiguration mWifiConfiguration ;
49
57
private Uri mCaCertUri ;
50
58
private Uri mUserCertUri ;
59
+ private String mUserCertAlias ;
51
60
52
61
private EditText mSsidEditText ;
53
62
private TextView mCaCertTextView ;
@@ -66,6 +75,7 @@ public static WifiEapTlsCreateDialogFragment newInstance(WifiConfiguration confi
66
75
@ Override
67
76
public void onCreate (Bundle savedInstanceState ) {
68
77
super .onCreate (savedInstanceState );
78
+ mDpm = getActivity ().getSystemService (DevicePolicyManager .class );
69
79
mWifiConfiguration = getArguments ().getParcelable (ARG_CONFIG );
70
80
if (mWifiConfiguration == null ) {
71
81
mWifiConfiguration = new WifiConfiguration ();
@@ -76,10 +86,19 @@ public void onCreate(Bundle savedInstanceState) {
76
86
public Dialog onCreateDialog (Bundle savedInstanceState ) {
77
87
LayoutInflater inflater = LayoutInflater .from (getActivity ());
78
88
View rootView = inflater .inflate (R .layout .eap_tls_wifi_config_dialog , null );
89
+
79
90
rootView .findViewById (R .id .import_ca_cert ).setOnClickListener (
80
91
new ImportButtonOnClickListener (REQUEST_CA_CERT , "application/x-x509-ca-cert" ));
81
92
rootView .findViewById (R .id .import_user_cert ).setOnClickListener (
82
93
new ImportButtonOnClickListener (REQUEST_USER_CERT , "application/x-pkcs12" ));
94
+
95
+ final Button selectUserCertButton = rootView .findViewById (R .id .select_user_cert );
96
+ if (SDK_INT >= VERSION_CODES .S ) {
97
+ selectUserCertButton .setOnClickListener (this ::onSelectClientCertClicked );
98
+ } else {
99
+ // KeyChain keys aren't supported.
100
+ selectUserCertButton .setVisibility (View .GONE );
101
+ }
83
102
mCaCertTextView = (TextView ) rootView .findViewById (R .id .selected_ca_cert );
84
103
mUserCertTextView = (TextView ) rootView .findViewById (R .id .selected_user_cert );
85
104
mSsidEditText = (EditText ) rootView .findViewById (R .id .ssid );
@@ -110,6 +129,20 @@ public void onClick(View view) {
110
129
return dialog ;
111
130
}
112
131
132
+ private void onSelectClientCertClicked (View view ) {
133
+ KeyChain .choosePrivateKeyAlias (getActivity (), alias -> {
134
+ if (alias == null ) {
135
+ // No value was chosen.
136
+ return ;
137
+ }
138
+ mUserCertAlias = alias ;
139
+ mUserCertUri = null ;
140
+
141
+ getActivity ().runOnUiThread (() ->
142
+ updateSelectedCert (mUserCertTextView , /* uri= */ null , alias ));
143
+ }, /* keyTypes[] */ null , /* issuers[] */ null , /* uri */ null , /* alias */ null );
144
+ }
145
+
113
146
private void populateUi () {
114
147
if (mWifiConfiguration == null ) {
115
148
return ;
@@ -119,8 +152,8 @@ private void populateUi() {
119
152
}
120
153
mIdentityEditText .setText (mWifiConfiguration .enterpriseConfig .getIdentity ());
121
154
// Both ca cert and client are not populated in the WifiConfiguration object.
122
- updateSelectedCert (mCaCertTextView , null );
123
- updateSelectedCert (mUserCertTextView , null );
155
+ updateSelectedCert (mCaCertTextView , null , null );
156
+ updateSelectedCert (mUserCertTextView , null , null );
124
157
}
125
158
126
159
private boolean extractInputDataAndSave () {
@@ -131,31 +164,18 @@ private boolean extractInputDataAndSave() {
131
164
} else {
132
165
mSsidEditText .setError (null );
133
166
}
134
- if (mCaCertUri == null ) {
135
- showToast (R .string .error_missing_ca_cert );
136
- return false ;
137
- }
138
- if (mUserCertUri == null ) {
139
- showToast (R .string .error_missing_client_cert );
140
- return false ;
141
- }
142
- X509Certificate caCert = parseX509Certificate (mCaCertUri );
143
- String certPassword = mCertPasswordEditText .getText ().toString ();
144
- CertificateUtil .PKCS12ParseInfo parseInfo = null ;
145
- try {
146
- parseInfo = CertificateUtil .parsePKCS12Certificate (
147
- getActivity ().getContentResolver (), mUserCertUri , certPassword );
148
- } catch (KeyStoreException | NoSuchAlgorithmException | IOException |
149
- CertificateException | UnrecoverableKeyException e ) {
150
- Log .e (TAG , "Fail to parse the input certificate: " , e );
151
- }
152
- if (parseInfo == null ) {
153
- showToast (R .string .error_missing_client_cert );
167
+
168
+ mWifiConfiguration .SSID = ssid ;
169
+ mWifiConfiguration .allowedKeyManagement .set (WifiConfiguration .KeyMgmt .WPA_EAP );
170
+ mWifiConfiguration .allowedKeyManagement .set (WifiConfiguration .KeyMgmt .IEEE8021X );
171
+
172
+ mWifiConfiguration .enterpriseConfig = extractEnterpriseConfig ();
173
+
174
+ if (mWifiConfiguration .enterpriseConfig == null ) {
154
175
return false ;
155
176
}
156
- String identity = mIdentityEditText .getText ().toString ();
157
- boolean success = saveWifiConfiguration (ssid , caCert , parseInfo .privateKey ,
158
- parseInfo .certificate , identity );
177
+
178
+ boolean success = WifiConfigUtil .saveWifiConfiguration (getActivity (), mWifiConfiguration );
159
179
if (success ) {
160
180
showToast (R .string .wifi_configs_header );
161
181
return true ;
@@ -165,20 +185,48 @@ private boolean extractInputDataAndSave() {
165
185
return false ;
166
186
}
167
187
168
- private boolean saveWifiConfiguration (String ssid , X509Certificate caCert ,
169
- PrivateKey privateKey , X509Certificate userCert , String identity ) {
170
- mWifiConfiguration .SSID = ssid ;
171
- mWifiConfiguration .allowedKeyManagement .set (WifiConfiguration .KeyMgmt .WPA_EAP );
172
- mWifiConfiguration .allowedKeyManagement .set (WifiConfiguration .KeyMgmt .IEEE8021X );
173
- WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig ();
174
- enterpriseConfig .setEapMethod (WifiEnterpriseConfig .Eap .TLS );
175
- enterpriseConfig .setCaCertificate (caCert );
176
- enterpriseConfig .setClientKeyEntry (privateKey , userCert );
188
+ private WifiEnterpriseConfig extractEnterpriseConfig () {
189
+ WifiEnterpriseConfig config = new WifiEnterpriseConfig ();
190
+ config .setEapMethod (WifiEnterpriseConfig .Eap .TLS );
191
+ String identity = mIdentityEditText .getText ().toString ();
192
+
177
193
if (!TextUtils .isEmpty (identity )) {
178
- enterpriseConfig .setIdentity (identity );
194
+ config .setIdentity (identity );
195
+ }
196
+
197
+ if (mCaCertUri == null ) {
198
+ showToast (R .string .error_missing_ca_cert );
199
+ return null ;
179
200
}
180
- mWifiConfiguration .enterpriseConfig = enterpriseConfig ;
181
- return WifiConfigUtil .saveWifiConfiguration (getActivity (), mWifiConfiguration );
201
+ config .setCaCertificate (parseX509Certificate (mCaCertUri ));
202
+
203
+ if (mUserCertUri != null ) {
204
+ final String certPassword = mCertPasswordEditText .getText ().toString ();
205
+ CertificateUtil .PKCS12ParseInfo parseInfo = null ;
206
+ try {
207
+ parseInfo = CertificateUtil .parsePKCS12Certificate (
208
+ getActivity ().getContentResolver (), mUserCertUri , certPassword );
209
+ } catch (KeyStoreException | NoSuchAlgorithmException | IOException |
210
+ CertificateException | UnrecoverableKeyException e ) {
211
+ Log .e (TAG , "Fail to parse the input certificate: " , e );
212
+ }
213
+ if (parseInfo == null ) {
214
+ showToast (R .string .error_missing_client_cert );
215
+ return null ;
216
+ }
217
+ config .setClientKeyEntry (parseInfo .privateKey , parseInfo .certificate );
218
+ } else if (mUserCertAlias != null ) {
219
+ if (!mDpm .grantKeyPairToWifiAuth (mUserCertAlias )) {
220
+ showToast (R .string .error_cannot_grant_to_wifi );
221
+ return null ;
222
+ }
223
+ config .setClientKeyPairAlias (mUserCertAlias );
224
+ } else {
225
+ showToast (R .string .error_missing_client_cert );
226
+ return null ;
227
+ }
228
+
229
+ return config ;
182
230
}
183
231
184
232
/**
@@ -217,28 +265,26 @@ public void onClick(View view) {
217
265
}
218
266
}
219
267
220
- private void updateSelectedCert (TextView textView , Uri uri ) {
221
- String displayName = null ;
222
- if (uri == null ) {
223
- displayName = getString (R .string .selected_certificate_none );
224
- } else {
268
+ private void updateSelectedCert (TextView textView , Uri uri , String alias ) {
269
+ final String selectedText ;
270
+ if (uri != null ) {
271
+ String displayName = null ;
225
272
final String [] projection = {MediaStore .MediaColumns .DISPLAY_NAME };
226
- Cursor cursor = getActivity ().getContentResolver ().query (uri , projection ,
227
- null , null , null );
228
- if (cursor != null ) {
229
- try {
230
- if (cursor .moveToFirst ()) {
231
- displayName = cursor .getString (0 );
232
- }
233
- } finally {
234
- cursor .close ();
273
+ try (Cursor cursor = getActivity ().getContentResolver ().query (
274
+ uri , projection , null , null , null )) {
275
+ if (cursor != null && cursor .moveToFirst ()) {
276
+ displayName = cursor .getString (0 );
235
277
}
236
278
}
237
- if (TextUtils .isEmpty (getString ( R . string . wifi_unknown_cert ) )) {
279
+ if (TextUtils .isEmpty (displayName )) {
238
280
displayName = getString (R .string .wifi_unknown_cert );
239
281
}
282
+ selectedText = getString (R .string .selected_certificate , displayName );
283
+ } else if (alias != null ) {
284
+ selectedText = getString (R .string .selected_keychain_certificate , alias );
285
+ } else {
286
+ selectedText = getString (R .string .selected_certificate_none );
240
287
}
241
- String selectedText = getString (R .string .selected_certificate , displayName );
242
288
textView .setText (selectedText );
243
289
}
244
290
@@ -252,11 +298,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
252
298
switch (requestCode ) {
253
299
case REQUEST_CA_CERT :
254
300
mCaCertUri = intent .getData ();
255
- updateSelectedCert (mCaCertTextView , mCaCertUri );
301
+ updateSelectedCert (mCaCertTextView , mCaCertUri , /* alias= */ null );
256
302
break ;
257
303
case REQUEST_USER_CERT :
258
304
mUserCertUri = intent .getData ();
259
- updateSelectedCert (mUserCertTextView , mUserCertUri );
305
+ mUserCertAlias = null ;
306
+ updateSelectedCert (mUserCertTextView , mUserCertUri , /* alias= */ null );
260
307
break ;
261
308
}
262
309
}
0 commit comments