Home | History | Annotate | Download | only in shill
      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;
     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 
     78 EapCredentials::EapCredentials() : use_system_cas_(true),
     79                                    use_proactive_key_caching_(false) {}
     80 
     81 EapCredentials::~EapCredentials() {}
     82 
     83 // static
     84 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
    171 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 
    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
    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 
    236 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 
    282 bool EapCredentials::IsConnectableUsingPassphrase() const {
    283   return !identity_.empty() && !password_.empty();
    284 }
    285 
    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 
    318 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 
    337 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 
    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 
    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 
    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 
    480 string EapCredentials::GetKeyManagement(Error* /*error*/) {
    481   return key_management_;
    482 }
    483 
    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 
    496 bool EapCredentials::ClientAuthenticationUsesCryptoToken() const {
    497   return (eap_.empty() || eap_ == kEapMethodTLS ||
    498           inner_eap_ == kEapMethodTLS) &&
    499          (!cert_id_.empty() || !key_id_.empty());
    500 }
    501 
    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 
    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