blob: 89f30d4b964b3088772b8c976a51f406113d55ad [file] [log] [blame]
Paul Stewartc43cbbe2013-04-11 06:29:30 -07001// 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
25using base::FilePath;
26using std::map;
27using std::string;
28using std::vector;
29
30using std::string;
31
32namespace shill {
33
34const char EapCredentials::kStorageEapAnonymousIdentity[] =
35 "EAP.AnonymousIdentity";
36const char EapCredentials::kStorageEapCACert[] = "EAP.CACert";
37const char EapCredentials::kStorageEapCACertID[] = "EAP.CACertID";
38const char EapCredentials::kStorageEapCACertNSS[] = "EAP.CACertNSS";
39const char EapCredentials::kStorageEapCACertPEM[] = "EAP.CACertPEM";
40const char EapCredentials::kStorageEapCertID[] = "EAP.CertID";
41const char EapCredentials::kStorageEapClientCert[] = "EAP.ClientCert";
42const char EapCredentials::kStorageEapEap[] = "EAP.EAP";
43const char EapCredentials::kStorageEapIdentity[] = "EAP.Identity";
44const char EapCredentials::kStorageEapInnerEap[] = "EAP.InnerEAP";
45const char EapCredentials::kStorageEapKeyID[] = "EAP.KeyID";
46const char EapCredentials::kStorageEapKeyManagement[] = "EAP.KeyMgmt";
47const char EapCredentials::kStorageEapPIN[] = "EAP.PIN";
48const char EapCredentials::kStorageEapPassword[] = "EAP.Password";
49const char EapCredentials::kStorageEapPrivateKey[] = "EAP.PrivateKey";
50const char EapCredentials::kStorageEapPrivateKeyPassword[] =
51 "EAP.PrivateKeyPassword";
52const char EapCredentials::kStorageEapSubjectMatch[] =
53 "EAP.SubjectMatch";
54const char EapCredentials::kStorageEapUseSystemCAs[] = "EAP.UseSystemCAs";
55
56EapCredentials::EapCredentials() : use_system_cas_(true) {}
57
58EapCredentials::~EapCredentials() {}
59
60// static
61void 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
147void 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
160void 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
197bool 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
211bool 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
258bool EapCredentials::IsConnectableUsingPassphrase() const {
259 return !identity_.empty() && !password_.empty();
260}
261
262void 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
292void 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
311void 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
411void EapCredentials::Reset() {
412 // Authentication properties.
413 anonymous_identity_ = "";
414 cert_id_ = "";
415 client_cert_ = "";
416 identity_ = "";
417 key_id_ = "";
Paul Stewart9956dc72013-04-23 14:06:17 -0700418 // Do not reset key_management_, since it should never be emptied.
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700419 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
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700435bool EapCredentials::SetEapPassword(const string &password, Error */*error*/) {
436 if (password_ == password) {
437 return false;
438 }
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700439 password_ = password;
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700440 return true;
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700441}
442
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700443bool EapCredentials::SetEapPrivateKeyPassword(const string &password,
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700444 Error */*error*/) {
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700445 if (private_key_password_ == password) {
446 return false;
447 }
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700448 private_key_password_ = password;
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700449 return true;
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700450}
451
452string EapCredentials::GetKeyManagement(Error */*error*/) {
453 return key_management_;
454}
455
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700456bool EapCredentials::SetKeyManagement(const std::string &key_management,
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700457 Error */*error*/) {
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700458 if (key_management.empty()) {
459 return false;
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700460 }
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700461 if (key_management_ == key_management) {
462 return false;
463 }
464 key_management_ = key_management;
465 return true;
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700466}
467
468void EapCredentials::HelpRegisterDerivedString(
469 PropertyStore *store,
470 const string &name,
471 string(EapCredentials::*get)(Error *),
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700472 bool(EapCredentials::*set)(const string&, Error *)) {
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700473 store->RegisterDerivedString(
474 name,
475 StringAccessor(new CustomAccessor<EapCredentials, string>(
476 this, get, set)));
477}
478
479void EapCredentials::HelpRegisterWriteOnlyDerivedString(
480 PropertyStore *store,
481 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700482 bool(EapCredentials::*set)(const string &, Error *),
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700483 void(EapCredentials::*clear)(Error *),
484 const string *default_value) {
485 store->RegisterDerivedString(
486 name,
487 StringAccessor(
488 new CustomWriteOnlyAccessor<EapCredentials, string>(
489 this, set, clear, default_value)));
490}
491
492}