1 //
2 // Copyright (C) 2013 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "shill/eap_credentials.h"
18
19 #include <map>
20 #include <string>
21 #include <utility>
22 #include <vector>
23
24 #if defined(__ANDROID__)
25 #include <dbus/service_constants.h>
26 #else
27 #include <chromeos/dbus/service_constants.h>
28 #endif // __ANDROID__
29
30 #include "shill/certificate_file.h"
31 #include "shill/key_value_store.h"
32 #include "shill/logging.h"
33 #include "shill/metrics.h"
34 #include "shill/property_accessor.h"
35 #include "shill/property_store.h"
36 #include "shill/service.h"
37 #include "shill/store_interface.h"
38 #include "shill/supplicant/wpa_supplicant.h"
39
40 using base::FilePath;
41 using std::map;
42 using std::string;
43 using std::vector;
44
45 using std::string;
46
47 namespace shill {
48
49 namespace Logging {
50 static auto kModuleLogScope = ScopeLogger::kService;
ObjectID(const EapCredentials * e)51 static string ObjectID(const EapCredentials* e) { return "(eap_credentials)"; }
52 }
53
54 const char EapCredentials::kStorageEapAnonymousIdentity[] =
55 "EAP.AnonymousIdentity";
56 const char EapCredentials::kStorageEapCACert[] = "EAP.CACert";
57 const char EapCredentials::kStorageEapCACertID[] = "EAP.CACertID";
58 const char EapCredentials::kStorageEapCACertNSS[] = "EAP.CACertNSS";
59 const char EapCredentials::kStorageEapCACertPEM[] = "EAP.CACertPEM";
60 const char EapCredentials::kStorageEapCertID[] = "EAP.CertID";
61 const char EapCredentials::kStorageEapClientCert[] = "EAP.ClientCert";
62 const char EapCredentials::kStorageEapEap[] = "EAP.EAP";
63 const char EapCredentials::kStorageEapIdentity[] = "EAP.Identity";
64 const char EapCredentials::kStorageEapInnerEap[] = "EAP.InnerEAP";
65 const char EapCredentials::kStorageEapKeyID[] = "EAP.KeyID";
66 const char EapCredentials::kStorageEapKeyManagement[] = "EAP.KeyMgmt";
67 const char EapCredentials::kStorageEapPIN[] = "EAP.PIN";
68 const char EapCredentials::kStorageEapPassword[] = "EAP.Password";
69 const char EapCredentials::kStorageEapPrivateKey[] = "EAP.PrivateKey";
70 const char EapCredentials::kStorageEapPrivateKeyPassword[] =
71 "EAP.PrivateKeyPassword";
72 const char EapCredentials::kStorageEapSubjectMatch[] =
73 "EAP.SubjectMatch";
74 const char EapCredentials::kStorageEapUseProactiveKeyCaching[] =
75 "EAP.UseProactiveKeyCaching";
76 const char EapCredentials::kStorageEapUseSystemCAs[] = "EAP.UseSystemCAs";
77
EapCredentials()78 EapCredentials::EapCredentials() : use_system_cas_(true),
79 use_proactive_key_caching_(false) {}
80
~EapCredentials()81 EapCredentials::~EapCredentials() {}
82
83 // static
PopulateSupplicantProperties(CertificateFile * certificate_file,KeyValueStore * params) const84 void EapCredentials::PopulateSupplicantProperties(
85 CertificateFile* certificate_file, KeyValueStore* params) const {
86 string ca_cert = ca_cert_;
87 if (!ca_cert_pem_.empty()) {
88 FilePath certfile =
89 certificate_file->CreatePEMFromStrings(ca_cert_pem_);
90 if (certfile.empty()) {
91 LOG(ERROR) << "Unable to extract PEM certificate.";
92 } else {
93 ca_cert = certfile.value();
94 }
95 }
96
97
98 typedef std::pair<const char*, const char*> KeyVal;
99 KeyVal init_propertyvals[] = {
100 // Authentication properties.
101 KeyVal(WPASupplicant::kNetworkPropertyEapAnonymousIdentity,
102 anonymous_identity_.c_str()),
103 KeyVal(WPASupplicant::kNetworkPropertyEapClientCert,
104 client_cert_.c_str()),
105 KeyVal(WPASupplicant::kNetworkPropertyEapIdentity, identity_.c_str()),
106 KeyVal(WPASupplicant::kNetworkPropertyEapCaPassword,
107 password_.c_str()),
108 KeyVal(WPASupplicant::kNetworkPropertyEapPrivateKey,
109 private_key_.c_str()),
110 KeyVal(WPASupplicant::kNetworkPropertyEapPrivateKeyPassword,
111 private_key_password_.c_str()),
112
113 // Non-authentication properties.
114 KeyVal(WPASupplicant::kNetworkPropertyEapCaCert, ca_cert.c_str()),
115 KeyVal(WPASupplicant::kNetworkPropertyEapCaCertId,
116 ca_cert_id_.c_str()),
117 KeyVal(WPASupplicant::kNetworkPropertyEapEap, eap_.c_str()),
118 KeyVal(WPASupplicant::kNetworkPropertyEapInnerEap,
119 inner_eap_.c_str()),
120 KeyVal(WPASupplicant::kNetworkPropertyEapSubjectMatch,
121 subject_match_.c_str())
122 };
123
124 vector<KeyVal> propertyvals(init_propertyvals,
125 init_propertyvals + arraysize(init_propertyvals));
126 if (use_system_cas_) {
127 propertyvals.push_back(KeyVal(
128 WPASupplicant::kNetworkPropertyCaPath, WPASupplicant::kCaPath));
129 } else if (ca_cert.empty()) {
130 LOG(WARNING) << __func__
131 << ": No certificate authorities are configured."
132 << " Server certificates will be accepted"
133 << " unconditionally.";
134 }
135
136 if (ClientAuthenticationUsesCryptoToken()) {
137 propertyvals.push_back(KeyVal(
138 WPASupplicant::kNetworkPropertyEapCertId, cert_id_.c_str()));
139 propertyvals.push_back(KeyVal(
140 WPASupplicant::kNetworkPropertyEapKeyId, key_id_.c_str()));
141 }
142
143 if (ClientAuthenticationUsesCryptoToken() || !ca_cert_id_.empty()) {
144 propertyvals.push_back(KeyVal(
145 WPASupplicant::kNetworkPropertyEapPin, pin_.c_str()));
146 propertyvals.push_back(KeyVal(
147 WPASupplicant::kNetworkPropertyEngineId,
148 WPASupplicant::kEnginePKCS11));
149 // We can't use the propertyvals vector for this since this argument
150 // is a uint32_t, not a string.
151 params->SetUint(WPASupplicant::kNetworkPropertyEngine,
152 WPASupplicant::kDefaultEngine);
153 }
154
155 if (use_proactive_key_caching_) {
156 params->SetUint(WPASupplicant::kNetworkPropertyEapProactiveKeyCaching,
157 WPASupplicant::kProactiveKeyCachingEnabled);
158 } else {
159 params->SetUint(WPASupplicant::kNetworkPropertyEapProactiveKeyCaching,
160 WPASupplicant::kProactiveKeyCachingDisabled);
161 }
162
163 for (const auto& keyval : propertyvals) {
164 if (strlen(keyval.second) > 0) {
165 params->SetString(keyval.first, keyval.second);
166 }
167 }
168 }
169
170 // static
PopulateWiMaxProperties(KeyValueStore * params) const171 void EapCredentials::PopulateWiMaxProperties(KeyValueStore* params) const {
172 if (!anonymous_identity_.empty()) {
173 params->SetString(wimax_manager::kEAPAnonymousIdentity,
174 anonymous_identity_);
175 }
176 if (!identity_.empty()) {
177 params->SetString(wimax_manager::kEAPUserIdentity, identity_);
178 }
179 if (!password_.empty()) {
180 params->SetString(wimax_manager::kEAPUserPassword, password_);
181 }
182 }
183
InitPropertyStore(PropertyStore * store)184 void EapCredentials::InitPropertyStore(PropertyStore* store) {
185 // Authentication properties.
186 store->RegisterString(kEapAnonymousIdentityProperty, &anonymous_identity_);
187 store->RegisterString(kEapCertIdProperty, &cert_id_);
188 store->RegisterString(kEapClientCertProperty, &client_cert_);
189 store->RegisterString(kEapIdentityProperty, &identity_);
190 store->RegisterString(kEapKeyIdProperty, &key_id_);
191 HelpRegisterDerivedString(store,
192 kEapKeyMgmtProperty,
193 &EapCredentials::GetKeyManagement,
194 &EapCredentials::SetKeyManagement);
195 HelpRegisterWriteOnlyDerivedString(store,
196 kEapPasswordProperty,
197 &EapCredentials::SetEapPassword,
198 nullptr,
199 &password_);
200 store->RegisterString(kEapPinProperty, &pin_);
201 store->RegisterString(kEapPrivateKeyProperty, &private_key_);
202 HelpRegisterWriteOnlyDerivedString(store,
203 kEapPrivateKeyPasswordProperty,
204 &EapCredentials::SetEapPrivateKeyPassword,
205 nullptr,
206 &private_key_password_);
207
208 // Non-authentication properties.
209 store->RegisterStrings(kEapCaCertPemProperty, &ca_cert_pem_);
210 store->RegisterString(kEapCaCertIdProperty, &ca_cert_id_);
211 store->RegisterString(kEapCaCertNssProperty, &ca_cert_nss_);
212 store->RegisterString(kEapCaCertProperty, &ca_cert_);
213 store->RegisterString(kEapMethodProperty, &eap_);
214 store->RegisterString(kEapPhase2AuthProperty, &inner_eap_);
215 store->RegisterString(kEapSubjectMatchProperty, &subject_match_);
216 store->RegisterBool(kEapUseProactiveKeyCachingProperty,
217 &use_proactive_key_caching_);
218 store->RegisterBool(kEapUseSystemCasProperty, &use_system_cas_);
219 }
220
221 // static
IsEapAuthenticationProperty(const string property)222 bool EapCredentials::IsEapAuthenticationProperty(const string property) {
223 return
224 property == kEapAnonymousIdentityProperty ||
225 property == kEapCertIdProperty ||
226 property == kEapClientCertProperty ||
227 property == kEapIdentityProperty ||
228 property == kEapKeyIdProperty ||
229 property == kEapKeyMgmtProperty ||
230 property == kEapPasswordProperty ||
231 property == kEapPinProperty ||
232 property == kEapPrivateKeyProperty ||
233 property == kEapPrivateKeyPasswordProperty;
234 }
235
IsConnectable() const236 bool EapCredentials::IsConnectable() const {
237 // Identity is required.
238 if (identity_.empty()) {
239 SLOG(this, 2) << "Not connectable: Identity is empty.";
240 return false;
241 }
242
243 if (!client_cert_.empty() || !cert_id_.empty()) {
244 // If a client certificate is being used, we must have a private key.
245 if (private_key_.empty() && key_id_.empty()) {
246 SLOG(this, 2)
247 << "Not connectable: Client certificate but no private key.";
248 return false;
249 }
250 }
251 if (!cert_id_.empty() || !key_id_.empty() ||
252 !ca_cert_id_.empty()) {
253 // If PKCS#11 data is needed, a PIN is required.
254 if (pin_.empty()) {
255 SLOG(this, 2) << "Not connectable: PKCS#11 data but no PIN.";
256 return false;
257 }
258 }
259
260 // For EAP-TLS, a client certificate is required.
261 if (eap_.empty() || eap_ == kEapMethodTLS) {
262 if ((!client_cert_.empty() || !cert_id_.empty()) &&
263 (!private_key_.empty() || !key_id_.empty())) {
264 SLOG(this, 2) << "Connectable: EAP-TLS with a client cert and key.";
265 return true;
266 }
267 }
268
269 // For EAP types other than TLS (e.g. EAP-TTLS or EAP-PEAP, password is the
270 // minimum requirement), at least an identity + password is required.
271 if (eap_.empty() || eap_ != kEapMethodTLS) {
272 if (!password_.empty()) {
273 SLOG(this, 2) << "Connectable. !EAP-TLS and has a password.";
274 return true;
275 }
276 }
277
278 SLOG(this, 2) << "Not connectable: No suitable EAP configuration was found.";
279 return false;
280 }
281
IsConnectableUsingPassphrase() const282 bool EapCredentials::IsConnectableUsingPassphrase() const {
283 return !identity_.empty() && !password_.empty();
284 }
285
Load(StoreInterface * storage,const string & id)286 void EapCredentials::Load(StoreInterface* storage, const string& id) {
287 // Authentication properties.
288 storage->GetCryptedString(id,
289 kStorageEapAnonymousIdentity,
290 &anonymous_identity_);
291 storage->GetString(id, kStorageEapCertID, &cert_id_);
292 storage->GetString(id, kStorageEapClientCert, &client_cert_);
293 storage->GetCryptedString(id, kStorageEapIdentity, &identity_);
294 storage->GetString(id, kStorageEapKeyID, &key_id_);
295 string key_management;
296 storage->GetString(id, kStorageEapKeyManagement, &key_management);
297 SetKeyManagement(key_management, nullptr);
298 storage->GetCryptedString(id, kStorageEapPassword, &password_);
299 storage->GetString(id, kStorageEapPIN, &pin_);
300 storage->GetString(id, kStorageEapPrivateKey, &private_key_);
301 storage->GetCryptedString(id,
302 kStorageEapPrivateKeyPassword,
303 &private_key_password_);
304
305 // Non-authentication properties.
306 storage->GetString(id, kStorageEapCACert, &ca_cert_);
307 storage->GetString(id, kStorageEapCACertID, &ca_cert_id_);
308 storage->GetString(id, kStorageEapCACertNSS, &ca_cert_nss_);
309 storage->GetStringList(id, kStorageEapCACertPEM, &ca_cert_pem_);
310 storage->GetString(id, kStorageEapEap, &eap_);
311 storage->GetString(id, kStorageEapInnerEap, &inner_eap_);
312 storage->GetString(id, kStorageEapSubjectMatch, &subject_match_);
313 storage->GetBool(id, kStorageEapUseProactiveKeyCaching,
314 &use_proactive_key_caching_);
315 storage->GetBool(id, kStorageEapUseSystemCAs, &use_system_cas_);
316 }
317
OutputConnectionMetrics(Metrics * metrics,Technology::Identifier technology) const318 void EapCredentials::OutputConnectionMetrics(
319 Metrics* metrics, Technology::Identifier technology) const {
320 Metrics::EapOuterProtocol outer_protocol =
321 Metrics::EapOuterProtocolStringToEnum(eap_);
322 metrics->SendEnumToUMA(
323 metrics->GetFullMetricName(Metrics::kMetricNetworkEapOuterProtocolSuffix,
324 technology),
325 outer_protocol,
326 Metrics::kMetricNetworkEapOuterProtocolMax);
327
328 Metrics::EapInnerProtocol inner_protocol =
329 Metrics::EapInnerProtocolStringToEnum(inner_eap_);
330 metrics->SendEnumToUMA(
331 metrics->GetFullMetricName(Metrics::kMetricNetworkEapInnerProtocolSuffix,
332 technology),
333 inner_protocol,
334 Metrics::kMetricNetworkEapInnerProtocolMax);
335 }
336
Save(StoreInterface * storage,const string & id,bool save_credentials) const337 void EapCredentials::Save(StoreInterface* storage, const string& id,
338 bool save_credentials) const {
339 // Authentication properties.
340 Service::SaveString(storage,
341 id,
342 kStorageEapAnonymousIdentity,
343 anonymous_identity_,
344 true,
345 save_credentials);
346 Service::SaveString(storage,
347 id,
348 kStorageEapCertID,
349 cert_id_,
350 false,
351 save_credentials);
352 Service::SaveString(storage,
353 id,
354 kStorageEapClientCert,
355 client_cert_,
356 false,
357 save_credentials);
358 Service::SaveString(storage,
359 id,
360 kStorageEapIdentity,
361 identity_,
362 true,
363 save_credentials);
364 Service::SaveString(storage,
365 id,
366 kStorageEapKeyID,
367 key_id_,
368 false,
369 save_credentials);
370 Service::SaveString(storage,
371 id,
372 kStorageEapKeyManagement,
373 key_management_,
374 false,
375 true);
376 Service::SaveString(storage,
377 id,
378 kStorageEapPassword,
379 password_,
380 true,
381 save_credentials);
382 Service::SaveString(storage,
383 id,
384 kStorageEapPIN,
385 pin_,
386 false,
387 save_credentials);
388 Service::SaveString(storage,
389 id,
390 kStorageEapPrivateKey,
391 private_key_,
392 false,
393 save_credentials);
394 Service::SaveString(storage,
395 id,
396 kStorageEapPrivateKeyPassword,
397 private_key_password_,
398 true,
399 save_credentials);
400
401 // Non-authentication properties.
402 Service::SaveString(storage, id, kStorageEapCACert, ca_cert_, false, true);
403 Service::SaveString(storage,
404 id,
405 kStorageEapCACertID,
406 ca_cert_id_,
407 false,
408 true);
409 Service::SaveString(storage,
410 id,
411 kStorageEapCACertNSS,
412 ca_cert_nss_,
413 false,
414 true);
415 if (ca_cert_pem_.empty()) {
416 storage->DeleteKey(id, kStorageEapCACertPEM);
417 } else {
418 storage->SetStringList(id, kStorageEapCACertPEM, ca_cert_pem_);
419 }
420 Service::SaveString(storage, id, kStorageEapEap, eap_, false, true);
421 Service::SaveString(storage,
422 id,
423 kStorageEapInnerEap,
424 inner_eap_,
425 false,
426 true);
427 Service::SaveString(storage,
428 id,
429 kStorageEapSubjectMatch,
430 subject_match_,
431 false,
432 true);
433 storage->SetBool(id, kStorageEapUseProactiveKeyCaching,
434 use_proactive_key_caching_);
435 storage->SetBool(id, kStorageEapUseSystemCAs, use_system_cas_);
436 }
437
Reset()438 void EapCredentials::Reset() {
439 // Authentication properties.
440 anonymous_identity_ = "";
441 cert_id_ = "";
442 client_cert_ = "";
443 identity_ = "";
444 key_id_ = "";
445 // Do not reset key_management_, since it should never be emptied.
446 password_ = "";
447 pin_ = "";
448 private_key_ = "";
449 private_key_password_ = "";
450
451 // Non-authentication properties.
452 ca_cert_ = "";
453 ca_cert_id_ = "";
454 ca_cert_nss_ = "";
455 ca_cert_pem_.clear();
456 eap_ = "";
457 inner_eap_ = "";
458 subject_match_ = "";
459 use_system_cas_ = true;
460 use_proactive_key_caching_ = false;
461 }
462
SetEapPassword(const string & password,Error *)463 bool EapCredentials::SetEapPassword(const string& password, Error* /*error*/) {
464 if (password_ == password) {
465 return false;
466 }
467 password_ = password;
468 return true;
469 }
470
SetEapPrivateKeyPassword(const string & password,Error *)471 bool EapCredentials::SetEapPrivateKeyPassword(const string& password,
472 Error* /*error*/) {
473 if (private_key_password_ == password) {
474 return false;
475 }
476 private_key_password_ = password;
477 return true;
478 }
479
GetKeyManagement(Error *)480 string EapCredentials::GetKeyManagement(Error* /*error*/) {
481 return key_management_;
482 }
483
SetKeyManagement(const std::string & key_management,Error *)484 bool EapCredentials::SetKeyManagement(const std::string& key_management,
485 Error* /*error*/) {
486 if (key_management.empty()) {
487 return false;
488 }
489 if (key_management_ == key_management) {
490 return false;
491 }
492 key_management_ = key_management;
493 return true;
494 }
495
ClientAuthenticationUsesCryptoToken() const496 bool EapCredentials::ClientAuthenticationUsesCryptoToken() const {
497 return (eap_.empty() || eap_ == kEapMethodTLS ||
498 inner_eap_ == kEapMethodTLS) &&
499 (!cert_id_.empty() || !key_id_.empty());
500 }
501
HelpRegisterDerivedString(PropertyStore * store,const string & name,string (EapCredentials::* get)(Error * error),bool (EapCredentials::* set)(const string &,Error *))502 void EapCredentials::HelpRegisterDerivedString(
503 PropertyStore* store,
504 const string& name,
505 string(EapCredentials::*get)(Error* error),
506 bool(EapCredentials::*set)(const string&, Error*)) {
507 store->RegisterDerivedString(
508 name,
509 StringAccessor(new CustomAccessor<EapCredentials, string>(
510 this, get, set)));
511 }
512
HelpRegisterWriteOnlyDerivedString(PropertyStore * store,const string & name,bool (EapCredentials::* set)(const string &,Error *),void (EapCredentials::* clear)(Error * error),const string * default_value)513 void EapCredentials::HelpRegisterWriteOnlyDerivedString(
514 PropertyStore* store,
515 const string& name,
516 bool(EapCredentials::*set)(const string&, Error*),
517 void(EapCredentials::*clear)(Error* error),
518 const string* default_value) {
519 store->RegisterDerivedString(
520 name,
521 StringAccessor(
522 new CustomWriteOnlyAccessor<EapCredentials, string>(
523 this, set, clear, default_value)));
524 }
525
526 } // namespace shill
527