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