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
40using base::FilePath;
41using std::map;
42using std::string;
43using std::vector;
44
45using std::string;
46
47namespace shill {
48
49namespace Logging {
50static auto kModuleLogScope = ScopeLogger::kService;
51static string ObjectID(const EapCredentials* e) { return "(eap_credentials)"; }
52}
53
54const char EapCredentials::kStorageEapAnonymousIdentity[] =
55    "EAP.AnonymousIdentity";
56const char EapCredentials::kStorageEapCACert[] = "EAP.CACert";
57const char EapCredentials::kStorageEapCACertID[] = "EAP.CACertID";
58const char EapCredentials::kStorageEapCACertNSS[] = "EAP.CACertNSS";
59const char EapCredentials::kStorageEapCACertPEM[] = "EAP.CACertPEM";
60const char EapCredentials::kStorageEapCertID[] = "EAP.CertID";
61const char EapCredentials::kStorageEapClientCert[] = "EAP.ClientCert";
62const char EapCredentials::kStorageEapEap[] = "EAP.EAP";
63const char EapCredentials::kStorageEapIdentity[] = "EAP.Identity";
64const char EapCredentials::kStorageEapInnerEap[] = "EAP.InnerEAP";
65const char EapCredentials::kStorageEapKeyID[] = "EAP.KeyID";
66const char EapCredentials::kStorageEapKeyManagement[] = "EAP.KeyMgmt";
67const char EapCredentials::kStorageEapPIN[] = "EAP.PIN";
68const char EapCredentials::kStorageEapPassword[] = "EAP.Password";
69const char EapCredentials::kStorageEapPrivateKey[] = "EAP.PrivateKey";
70const char EapCredentials::kStorageEapPrivateKeyPassword[] =
71    "EAP.PrivateKeyPassword";
72const char EapCredentials::kStorageEapSubjectMatch[] =
73    "EAP.SubjectMatch";
74const char EapCredentials::kStorageEapUseProactiveKeyCaching[] =
75    "EAP.UseProactiveKeyCaching";
76const char EapCredentials::kStorageEapUseSystemCAs[] = "EAP.UseSystemCAs";
77
78EapCredentials::EapCredentials() : use_system_cas_(true),
79                                   use_proactive_key_caching_(false) {}
80
81EapCredentials::~EapCredentials() {}
82
83// static
84void 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
171void 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
184void 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
222bool 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
236bool 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
282bool EapCredentials::IsConnectableUsingPassphrase() const {
283  return !identity_.empty() && !password_.empty();
284}
285
286void 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
318void 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
337void 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
438void 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
463bool EapCredentials::SetEapPassword(const string& password, Error* /*error*/) {
464  if (password_ == password) {
465    return false;
466  }
467  password_ = password;
468  return true;
469}
470
471bool 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
480string EapCredentials::GetKeyManagement(Error* /*error*/) {
481  return key_management_;
482}
483
484bool 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
496bool EapCredentials::ClientAuthenticationUsesCryptoToken() const {
497  return (eap_.empty() || eap_ == kEapMethodTLS ||
498          inner_eap_ == kEapMethodTLS) &&
499         (!cert_id_.empty() || !key_id_.empty());
500}
501
502void 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
513void 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