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