Paul Stewart | c43cbbe | 2013-04-11 06:29:30 -0700 | [diff] [blame] | 1 | // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "shill/eap_credentials.h" |
| 6 | |
| 7 | #include <map> |
| 8 | #include <string> |
| 9 | #include <utility> |
| 10 | #include <vector> |
| 11 | |
| 12 | #include <chromeos/dbus/service_constants.h> |
| 13 | |
| 14 | #include "shill/certificate_file.h" |
| 15 | #include "shill/logging.h" |
| 16 | #include "shill/key_value_store.h" |
| 17 | #include "shill/metrics.h" |
| 18 | #include "shill/nss.h" |
| 19 | #include "shill/property_accessor.h" |
| 20 | #include "shill/property_store.h" |
| 21 | #include "shill/service.h" |
| 22 | #include "shill/store_interface.h" |
| 23 | #include "shill/wpa_supplicant.h" |
| 24 | |
| 25 | using base::FilePath; |
| 26 | using std::map; |
| 27 | using std::string; |
| 28 | using std::vector; |
| 29 | |
| 30 | using std::string; |
| 31 | |
| 32 | namespace shill { |
| 33 | |
| 34 | const char EapCredentials::kStorageEapAnonymousIdentity[] = |
| 35 | "EAP.AnonymousIdentity"; |
| 36 | const char EapCredentials::kStorageEapCACert[] = "EAP.CACert"; |
| 37 | const char EapCredentials::kStorageEapCACertID[] = "EAP.CACertID"; |
| 38 | const char EapCredentials::kStorageEapCACertNSS[] = "EAP.CACertNSS"; |
| 39 | const char EapCredentials::kStorageEapCACertPEM[] = "EAP.CACertPEM"; |
| 40 | const char EapCredentials::kStorageEapCertID[] = "EAP.CertID"; |
| 41 | const char EapCredentials::kStorageEapClientCert[] = "EAP.ClientCert"; |
| 42 | const char EapCredentials::kStorageEapEap[] = "EAP.EAP"; |
| 43 | const char EapCredentials::kStorageEapIdentity[] = "EAP.Identity"; |
| 44 | const char EapCredentials::kStorageEapInnerEap[] = "EAP.InnerEAP"; |
| 45 | const char EapCredentials::kStorageEapKeyID[] = "EAP.KeyID"; |
| 46 | const char EapCredentials::kStorageEapKeyManagement[] = "EAP.KeyMgmt"; |
| 47 | const char EapCredentials::kStorageEapPIN[] = "EAP.PIN"; |
| 48 | const char EapCredentials::kStorageEapPassword[] = "EAP.Password"; |
| 49 | const char EapCredentials::kStorageEapPrivateKey[] = "EAP.PrivateKey"; |
| 50 | const char EapCredentials::kStorageEapPrivateKeyPassword[] = |
| 51 | "EAP.PrivateKeyPassword"; |
| 52 | const char EapCredentials::kStorageEapSubjectMatch[] = |
| 53 | "EAP.SubjectMatch"; |
| 54 | const char EapCredentials::kStorageEapUseSystemCAs[] = "EAP.UseSystemCAs"; |
| 55 | |
| 56 | EapCredentials::EapCredentials() : use_system_cas_(true) {} |
| 57 | |
| 58 | EapCredentials::~EapCredentials() {} |
| 59 | |
| 60 | // static |
| 61 | void EapCredentials::PopulateSupplicantProperties( |
| 62 | CertificateFile *certificate_file, |
| 63 | NSS *nss, |
| 64 | const vector<char> nss_identifier, |
| 65 | map<string, DBus::Variant> *params) const { |
| 66 | string ca_cert = ca_cert_; |
| 67 | if (!ca_cert_pem_.empty()) { |
| 68 | FilePath certfile = |
| 69 | certificate_file->CreateDERFromString(ca_cert_pem_); |
| 70 | if (certfile.empty()) { |
| 71 | LOG(ERROR) << "Unable to extract PEM certificate."; |
| 72 | } else { |
| 73 | ca_cert = certfile.value(); |
| 74 | } |
| 75 | } else if (!ca_cert_nss_.empty()) { |
| 76 | FilePath certfile = nss->GetDERCertfile(ca_cert_nss_, nss_identifier); |
| 77 | if (certfile.empty()) { |
| 78 | LOG(ERROR) << "Unable to extract DER certificate: " << ca_cert_nss_; |
| 79 | } else { |
| 80 | ca_cert = certfile.value(); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | |
| 85 | typedef std::pair<const char *, const char *> KeyVal; |
| 86 | KeyVal init_propertyvals[] = { |
| 87 | // Authentication properties. |
| 88 | KeyVal(WPASupplicant::kNetworkPropertyEapAnonymousIdentity, |
| 89 | anonymous_identity_.c_str()), |
| 90 | KeyVal(WPASupplicant::kNetworkPropertyEapCertId, cert_id_.c_str()), |
| 91 | KeyVal(WPASupplicant::kNetworkPropertyEapClientCert, |
| 92 | client_cert_.c_str()), |
| 93 | KeyVal(WPASupplicant::kNetworkPropertyEapIdentity, identity_.c_str()), |
| 94 | KeyVal(WPASupplicant::kNetworkPropertyEapKeyId, key_id_.c_str()), |
| 95 | KeyVal(WPASupplicant::kNetworkPropertyEapCaPassword, |
| 96 | password_.c_str()), |
| 97 | KeyVal(WPASupplicant::kNetworkPropertyEapPrivateKey, |
| 98 | private_key_.c_str()), |
| 99 | KeyVal(WPASupplicant::kNetworkPropertyEapPrivateKeyPassword, |
| 100 | private_key_password_.c_str()), |
| 101 | |
| 102 | // Non-authentication properties. |
| 103 | KeyVal(WPASupplicant::kNetworkPropertyEapCaCert, ca_cert.c_str()), |
| 104 | KeyVal(WPASupplicant::kNetworkPropertyEapCaCertId, |
| 105 | ca_cert_id_.c_str()), |
| 106 | KeyVal(WPASupplicant::kNetworkPropertyEapEap, eap_.c_str()), |
| 107 | KeyVal(WPASupplicant::kNetworkPropertyEapInnerEap, |
| 108 | inner_eap_.c_str()), |
| 109 | KeyVal(WPASupplicant::kNetworkPropertyEapSubjectMatch, |
| 110 | subject_match_.c_str()) |
| 111 | }; |
| 112 | |
| 113 | vector<KeyVal> propertyvals(init_propertyvals, |
| 114 | init_propertyvals + arraysize(init_propertyvals)); |
| 115 | if (use_system_cas_) { |
| 116 | propertyvals.push_back(KeyVal( |
| 117 | WPASupplicant::kNetworkPropertyCaPath, WPASupplicant::kCaPath)); |
| 118 | } else if (ca_cert.empty()) { |
| 119 | LOG(WARNING) << __func__ |
| 120 | << ": No certificate authorities are configured." |
| 121 | << " Server certificates will be accepted" |
| 122 | << " unconditionally."; |
| 123 | } |
| 124 | |
| 125 | if (!cert_id_.empty() || !key_id_.empty() || |
| 126 | !ca_cert_id_.empty()) { |
| 127 | propertyvals.push_back(KeyVal( |
| 128 | WPASupplicant::kNetworkPropertyEapPin, pin_.c_str())); |
| 129 | propertyvals.push_back(KeyVal( |
| 130 | WPASupplicant::kNetworkPropertyEngineId, |
| 131 | WPASupplicant::kEnginePKCS11)); |
| 132 | // We can't use the propertyvals vector for this since this argument |
| 133 | // is a uint32, not a string. |
| 134 | (*params)[WPASupplicant::kNetworkPropertyEngine].writer(). |
| 135 | append_uint32(WPASupplicant::kDefaultEngine); |
| 136 | } |
| 137 | |
| 138 | vector<KeyVal>::iterator it; |
| 139 | for (it = propertyvals.begin(); it != propertyvals.end(); ++it) { |
| 140 | if (strlen((*it).second) > 0) { |
| 141 | (*params)[(*it).first].writer().append_string((*it).second); |
| 142 | } |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | // static |
| 147 | void EapCredentials::PopulateWiMaxProperties(KeyValueStore *params) const { |
| 148 | if (!anonymous_identity_.empty()) { |
| 149 | params->SetString(wimax_manager::kEAPAnonymousIdentity, |
| 150 | anonymous_identity_); |
| 151 | } |
| 152 | if (!identity_.empty()) { |
| 153 | params->SetString(wimax_manager::kEAPUserIdentity, identity_); |
| 154 | } |
| 155 | if (!password_.empty()) { |
| 156 | params->SetString(wimax_manager::kEAPUserPassword, password_); |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | void EapCredentials::InitPropertyStore(PropertyStore *store) { |
| 161 | // Authentication properties. |
| 162 | store->RegisterString(flimflam::kEapAnonymousIdentityProperty, |
| 163 | &anonymous_identity_); |
| 164 | store->RegisterString(flimflam::kEAPCertIDProperty, &cert_id_); |
| 165 | store->RegisterString(flimflam::kEAPClientCertProperty, &client_cert_); |
| 166 | store->RegisterString(flimflam::kEapIdentityProperty, &identity_); |
| 167 | store->RegisterString(flimflam::kEAPKeyIDProperty, &key_id_); |
| 168 | HelpRegisterDerivedString(store, |
| 169 | flimflam::kEapKeyMgmtProperty, |
| 170 | &EapCredentials::GetKeyManagement, |
| 171 | &EapCredentials::SetKeyManagement); |
| 172 | HelpRegisterWriteOnlyDerivedString(store, |
| 173 | flimflam::kEapPasswordProperty, |
| 174 | &EapCredentials::SetEapPassword, |
| 175 | NULL, |
| 176 | &password_); |
| 177 | store->RegisterString(flimflam::kEAPPINProperty, &pin_); |
| 178 | store->RegisterString(flimflam::kEapPrivateKeyProperty, &private_key_); |
| 179 | HelpRegisterWriteOnlyDerivedString(store, |
| 180 | flimflam::kEapPrivateKeyPasswordProperty, |
| 181 | &EapCredentials::SetEapPrivateKeyPassword, |
| 182 | NULL, |
| 183 | &private_key_password_); |
| 184 | |
| 185 | // Non-authentication properties. |
| 186 | store->RegisterString(kEapCaCertPemProperty, &ca_cert_pem_); |
| 187 | store->RegisterString(flimflam::kEapCaCertIDProperty, &ca_cert_id_); |
| 188 | store->RegisterString(flimflam::kEapCaCertNssProperty, &ca_cert_nss_); |
| 189 | store->RegisterString(flimflam::kEapCaCertProperty, &ca_cert_); |
| 190 | store->RegisterString(flimflam::kEAPEAPProperty, &eap_); |
| 191 | store->RegisterString(flimflam::kEapPhase2AuthProperty, &inner_eap_); |
| 192 | store->RegisterString(kEapSubjectMatchProperty, &subject_match_); |
| 193 | store->RegisterBool(flimflam::kEapUseSystemCAsProperty, &use_system_cas_); |
| 194 | } |
| 195 | |
| 196 | // static |
| 197 | bool EapCredentials::IsEapAuthenticationProperty(const string property) { |
| 198 | return |
| 199 | property == flimflam::kEapAnonymousIdentityProperty || |
| 200 | property == flimflam::kEAPCertIDProperty || |
| 201 | property == flimflam::kEAPClientCertProperty || |
| 202 | property == flimflam::kEapIdentityProperty || |
| 203 | property == flimflam::kEAPKeyIDProperty || |
| 204 | property == flimflam::kEapKeyMgmtProperty || |
| 205 | property == flimflam::kEapPasswordProperty || |
| 206 | property == flimflam::kEAPPINProperty || |
| 207 | property == flimflam::kEapPrivateKeyProperty || |
| 208 | property == flimflam::kEapPrivateKeyPasswordProperty; |
| 209 | } |
| 210 | |
| 211 | bool EapCredentials::IsConnectable() const { |
| 212 | // Identity is required. |
| 213 | if (identity_.empty()) { |
| 214 | SLOG(Service, 2) << "Not connectable: Identity is empty."; |
| 215 | return false; |
| 216 | } |
| 217 | |
| 218 | if (!client_cert_.empty() || !cert_id_.empty()) { |
| 219 | // If a client certificate is being used, we must have a private key. |
| 220 | if (private_key_.empty() && key_id_.empty()) { |
| 221 | SLOG(Service, 2) |
| 222 | << "Not connectable: Client certificate but no private key."; |
| 223 | return false; |
| 224 | } |
| 225 | } |
| 226 | if (!cert_id_.empty() || !key_id_.empty() || |
| 227 | !ca_cert_id_.empty()) { |
| 228 | // If PKCS#11 data is needed, a PIN is required. |
| 229 | if (pin_.empty()) { |
| 230 | SLOG(Service, 2) << "Not connectable: PKCS#11 data but no PIN."; |
| 231 | return false; |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | // For EAP-TLS, a client certificate is required. |
| 236 | if (eap_.empty() || eap_ == "TLS") { |
| 237 | if ((!client_cert_.empty() || !cert_id_.empty()) && |
| 238 | (!private_key_.empty() || !key_id_.empty())) { |
| 239 | SLOG(Service, 2) << "Connectable: EAP-TLS with a client cert and key."; |
| 240 | return true; |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | // For EAP types other than TLS (e.g. EAP-TTLS or EAP-PEAP, password is the |
| 245 | // minimum requirement), at least an identity + password is required. |
| 246 | if (eap_.empty() || eap_ != "TLS") { |
| 247 | if (!password_.empty()) { |
| 248 | SLOG(Service, 2) << "Connectable. !EAP-TLS and has a password."; |
| 249 | return true; |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | SLOG(Service, 2) |
| 254 | << "Not connectable: No suitable EAP configuration was found."; |
| 255 | return false; |
| 256 | } |
| 257 | |
| 258 | bool EapCredentials::IsConnectableUsingPassphrase() const { |
| 259 | return !identity_.empty() && !password_.empty(); |
| 260 | } |
| 261 | |
| 262 | void EapCredentials::Load(StoreInterface *storage, const string &id) { |
| 263 | // Authentication properties. |
| 264 | storage->GetCryptedString(id, |
| 265 | kStorageEapAnonymousIdentity, |
| 266 | &anonymous_identity_); |
| 267 | storage->GetString(id, kStorageEapCertID, &cert_id_); |
| 268 | storage->GetString(id, kStorageEapClientCert, &client_cert_); |
| 269 | storage->GetCryptedString(id, kStorageEapIdentity, &identity_); |
| 270 | storage->GetString(id, kStorageEapKeyID, &key_id_); |
| 271 | string key_management; |
| 272 | storage->GetString(id, kStorageEapKeyManagement, &key_management); |
| 273 | SetKeyManagement(key_management, NULL); |
| 274 | storage->GetCryptedString(id, kStorageEapPassword, &password_); |
| 275 | storage->GetString(id, kStorageEapPIN, &pin_); |
| 276 | storage->GetString(id, kStorageEapPrivateKey, &private_key_); |
| 277 | storage->GetCryptedString(id, |
| 278 | kStorageEapPrivateKeyPassword, |
| 279 | &private_key_password_); |
| 280 | |
| 281 | // Non-authentication properties. |
| 282 | storage->GetString(id, kStorageEapCACert, &ca_cert_); |
| 283 | storage->GetString(id, kStorageEapCACertID, &ca_cert_id_); |
| 284 | storage->GetString(id, kStorageEapCACertNSS, &ca_cert_nss_); |
| 285 | storage->GetString(id, kStorageEapCACertPEM, &ca_cert_pem_); |
| 286 | storage->GetString(id, kStorageEapEap, &eap_); |
| 287 | storage->GetString(id, kStorageEapInnerEap, &inner_eap_); |
| 288 | storage->GetString(id, kStorageEapSubjectMatch, &subject_match_); |
| 289 | storage->GetBool(id, kStorageEapUseSystemCAs, &use_system_cas_); |
| 290 | } |
| 291 | |
| 292 | void EapCredentials::OutputConnectionMetrics( |
| 293 | Metrics *metrics, Technology::Identifier technology) const { |
| 294 | Metrics::EapOuterProtocol outer_protocol = |
| 295 | Metrics::EapOuterProtocolStringToEnum(eap_); |
| 296 | metrics->SendEnumToUMA( |
| 297 | metrics->GetFullMetricName(Metrics::kMetricNetworkEapOuterProtocol, |
| 298 | technology), |
| 299 | outer_protocol, |
| 300 | Metrics::kMetricNetworkEapOuterProtocolMax); |
| 301 | |
| 302 | Metrics::EapInnerProtocol inner_protocol = |
| 303 | Metrics::EapInnerProtocolStringToEnum(inner_eap_); |
| 304 | metrics->SendEnumToUMA( |
| 305 | metrics->GetFullMetricName(Metrics::kMetricNetworkEapInnerProtocol, |
| 306 | technology), |
| 307 | inner_protocol, |
| 308 | Metrics::kMetricNetworkEapInnerProtocolMax); |
| 309 | } |
| 310 | |
| 311 | void EapCredentials::Save(StoreInterface *storage, const string &id, |
| 312 | bool save_credentials) const { |
| 313 | // Authentication properties. |
| 314 | Service::SaveString(storage, |
| 315 | id, |
| 316 | kStorageEapAnonymousIdentity, |
| 317 | anonymous_identity_, |
| 318 | true, |
| 319 | save_credentials); |
| 320 | Service::SaveString(storage, |
| 321 | id, |
| 322 | kStorageEapCertID, |
| 323 | cert_id_, |
| 324 | false, |
| 325 | save_credentials); |
| 326 | Service::SaveString(storage, |
| 327 | id, |
| 328 | kStorageEapClientCert, |
| 329 | client_cert_, |
| 330 | false, |
| 331 | save_credentials); |
| 332 | Service::SaveString(storage, |
| 333 | id, |
| 334 | kStorageEapIdentity, |
| 335 | identity_, |
| 336 | true, |
| 337 | save_credentials); |
| 338 | Service::SaveString(storage, |
| 339 | id, |
| 340 | kStorageEapKeyID, |
| 341 | key_id_, |
| 342 | false, |
| 343 | save_credentials); |
| 344 | Service::SaveString(storage, |
| 345 | id, |
| 346 | kStorageEapKeyManagement, |
| 347 | key_management_, |
| 348 | false, |
| 349 | true); |
| 350 | Service::SaveString(storage, |
| 351 | id, |
| 352 | kStorageEapPassword, |
| 353 | password_, |
| 354 | true, |
| 355 | save_credentials); |
| 356 | Service::SaveString(storage, |
| 357 | id, |
| 358 | kStorageEapPIN, |
| 359 | pin_, |
| 360 | false, |
| 361 | save_credentials); |
| 362 | Service::SaveString(storage, |
| 363 | id, |
| 364 | kStorageEapPrivateKey, |
| 365 | private_key_, |
| 366 | false, |
| 367 | save_credentials); |
| 368 | Service::SaveString(storage, |
| 369 | id, |
| 370 | kStorageEapPrivateKeyPassword, |
| 371 | private_key_password_, |
| 372 | true, |
| 373 | save_credentials); |
| 374 | |
| 375 | // Non-authentication properties. |
| 376 | Service::SaveString(storage, id, kStorageEapCACert, ca_cert_, false, true); |
| 377 | Service::SaveString(storage, |
| 378 | id, |
| 379 | kStorageEapCACertID, |
| 380 | ca_cert_id_, |
| 381 | false, |
| 382 | true); |
| 383 | Service::SaveString(storage, |
| 384 | id, |
| 385 | kStorageEapCACertNSS, |
| 386 | ca_cert_nss_, |
| 387 | false, |
| 388 | true); |
| 389 | Service::SaveString(storage, |
| 390 | id, |
| 391 | kStorageEapCACertPEM, |
| 392 | ca_cert_pem_, |
| 393 | false, |
| 394 | true); |
| 395 | Service::SaveString(storage, id, kStorageEapEap, eap_, false, true); |
| 396 | Service::SaveString(storage, |
| 397 | id, |
| 398 | kStorageEapInnerEap, |
| 399 | inner_eap_, |
| 400 | false, |
| 401 | true); |
| 402 | Service::SaveString(storage, |
| 403 | id, |
| 404 | kStorageEapSubjectMatch, |
| 405 | subject_match_, |
| 406 | false, |
| 407 | true); |
| 408 | storage->SetBool(id, kStorageEapUseSystemCAs, use_system_cas_); |
| 409 | } |
| 410 | |
| 411 | void EapCredentials::Reset() { |
| 412 | // Authentication properties. |
| 413 | anonymous_identity_ = ""; |
| 414 | cert_id_ = ""; |
| 415 | client_cert_ = ""; |
| 416 | identity_ = ""; |
| 417 | key_id_ = ""; |
| 418 | key_management_ = ""; |
| 419 | password_ = ""; |
| 420 | pin_ = ""; |
| 421 | private_key_ = ""; |
| 422 | private_key_password_ = ""; |
| 423 | |
| 424 | // Non-authentication properties. |
| 425 | ca_cert_ = ""; |
| 426 | ca_cert_id_ = ""; |
| 427 | ca_cert_nss_ = ""; |
| 428 | ca_cert_pem_ = ""; |
| 429 | eap_ = ""; |
| 430 | inner_eap_ = ""; |
| 431 | subject_match_ = ""; |
| 432 | use_system_cas_ = true; |
| 433 | } |
| 434 | |
| 435 | void EapCredentials::SetEapPassword(const string &password, Error */*error*/) { |
| 436 | password_ = password; |
| 437 | } |
| 438 | |
| 439 | void EapCredentials::SetEapPrivateKeyPassword(const string &password, |
| 440 | Error */*error*/) { |
| 441 | private_key_password_ = password; |
| 442 | } |
| 443 | |
| 444 | string EapCredentials::GetKeyManagement(Error */*error*/) { |
| 445 | return key_management_; |
| 446 | } |
| 447 | |
| 448 | void EapCredentials::SetKeyManagement(const std::string &key_management, |
| 449 | Error */*error*/) { |
| 450 | if (!key_management.empty()) { |
| 451 | key_management_ = key_management; |
| 452 | } |
| 453 | } |
| 454 | |
| 455 | void EapCredentials::HelpRegisterDerivedString( |
| 456 | PropertyStore *store, |
| 457 | const string &name, |
| 458 | string(EapCredentials::*get)(Error *), |
| 459 | void(EapCredentials::*set)(const string&, Error *)) { |
| 460 | store->RegisterDerivedString( |
| 461 | name, |
| 462 | StringAccessor(new CustomAccessor<EapCredentials, string>( |
| 463 | this, get, set))); |
| 464 | } |
| 465 | |
| 466 | void EapCredentials::HelpRegisterWriteOnlyDerivedString( |
| 467 | PropertyStore *store, |
| 468 | const string &name, |
| 469 | void(EapCredentials::*set)(const string &, Error *), |
| 470 | void(EapCredentials::*clear)(Error *), |
| 471 | const string *default_value) { |
| 472 | store->RegisterDerivedString( |
| 473 | name, |
| 474 | StringAccessor( |
| 475 | new CustomWriteOnlyAccessor<EapCredentials, string>( |
| 476 | this, set, clear, default_value))); |
| 477 | } |
| 478 | |
| 479 | } |