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