blob: 25e859374145100457aa51d098009091ef44d696 [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 <base/stl_util.h>
8#include <chromeos/dbus/service_constants.h>
9#include <gtest/gtest.h>
10
11#include "shill/key_value_store.h"
12#include "shill/mock_certificate_file.h"
13#include "shill/mock_event_dispatcher.h"
14#include "shill/mock_log.h"
15#include "shill/mock_metrics.h"
16#include "shill/mock_nss.h"
17#include "shill/mock_property_store.h"
18#include "shill/mock_store.h"
19#include "shill/technology.h"
20#include "shill/wpa_supplicant.h"
21
22using base::FilePath;
23using std::map;
24using std::string;
25using std::vector;
26using testing::_;
27using testing::AnyNumber;
28using testing::DoAll;
29using testing::HasSubstr;
30using testing::Mock;
31using testing::Return;
32using testing::SetArgumentPointee;
33
34namespace shill {
35
36class EapCredentialsTest : public testing::Test {
37 public:
38 EapCredentialsTest() {}
39 virtual ~EapCredentialsTest() {}
40
41 protected:
42 void PopulateSupplicantProperties() {
43 eap_.PopulateSupplicantProperties(&certificate_file_, &nss_,
44 nss_identifier_, &params_);
45 }
46
47 void SetAnonymousIdentity(const string &anonymous_identity) {
48 eap_.anonymous_identity_ = anonymous_identity;
49 }
50 void SetCACertNSS(const string &ca_cert_nss) {
51 eap_.ca_cert_nss_ = ca_cert_nss;
52 }
53 void SetCACertPEM(const string &ca_cert_pem) {
54 eap_.ca_cert_pem_ = ca_cert_pem;
55 }
56 void SetClientCert(const string &client_cert) {
57 eap_.client_cert_ = client_cert;
58 }
59 void SetCertId(const string &cert_id) {
60 eap_.cert_id_ = cert_id;
61 }
62 void SetEap(const string &eap) {
63 eap_.eap_ = eap;
64 }
65 void SetIdentity(const string &identity) {
66 eap_.identity_ = identity;
67 }
68 void SetInnerEap(const string &inner_eap) {
69 eap_.inner_eap_ = inner_eap;
70 }
71 void SetKeyId(const string &key_id) {
72 eap_.key_id_ = key_id;
73 }
74 const string &GetPassword() {
75 return eap_.password_;
76 }
77 void SetPassword(const string &password) {
78 eap_.password_ = password;
79 }
80 void SetPrivateKey(const string &private_key) {
81 eap_.private_key_ = private_key;
82 }
83 void SetPin(const string &pin) {
84 eap_.pin_ = pin;
85 }
86 void SetUseSystemCAs(bool use_system_cas) {
87 eap_.use_system_cas_ = use_system_cas;
88 }
89 bool IsReset() {
90 return
91 eap_.anonymous_identity_.empty() &&
92 eap_.cert_id_.empty() &&
93 eap_.client_cert_.empty() &&
94 eap_.identity_.empty() &&
95 eap_.key_id_.empty() &&
Paul Stewartc43cbbe2013-04-11 06:29:30 -070096 eap_.password_.empty() &&
97 eap_.pin_.empty() &&
98 eap_.private_key_.empty() &&
99 eap_.private_key_password_.empty() &&
100 eap_.ca_cert_.empty() &&
101 eap_.ca_cert_id_.empty() &&
102 eap_.ca_cert_nss_.empty() &&
103 eap_.ca_cert_pem_.empty() &&
104 eap_.eap_.empty() &&
105 eap_.inner_eap_.empty() &&
106 eap_.subject_match_.empty() &&
107 eap_.use_system_cas_;
108 }
109
Paul Stewart9956dc72013-04-23 14:06:17 -0700110 const string &GetKeyManagement() {
111 return eap_.key_management_;
112 }
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700113 bool SetEapPassword(const string &password, Error *error) {
114 return eap_.SetEapPassword(password, error);
115 }
116 bool SetEapPrivateKeyPassword(const string &password, Error *error) {
117 return eap_.SetEapPrivateKeyPassword(password, error);
118 }
Paul Stewart9956dc72013-04-23 14:06:17 -0700119
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700120 EapCredentials eap_;
121 MockCertificateFile certificate_file_;
122 MockNSS nss_;
123 vector<char> nss_identifier_;
124 map<string, ::DBus::Variant> params_;
125};
126
127TEST_F(EapCredentialsTest, PropertyStore) {
128 PropertyStore store;
129 eap_.InitPropertyStore(&store);
130 const string kIdentity("Cross-Eyed Mary");
131 Error error;
132 EXPECT_TRUE(store.SetStringProperty(flimflam::kEapIdentityProperty,
133 kIdentity, &error));
134 EXPECT_EQ(kIdentity, eap_.identity());
135}
136
137TEST_F(EapCredentialsTest, Connectable) {
138 // Empty EAP credentials should not make a 802.1x network connectable.
139 EXPECT_FALSE(eap_.IsConnectable());
140
141 // Identity alone is not enough.
142 SetIdentity("Steel Monkey");
143 EXPECT_FALSE(eap_.IsConnectable());
144
145 // Set a password.
146 SetPassword("Angry Tapir");
147
148 // Empty "EAP" parameter is treated like "not EAP-TLS", and connectable.
149 EXPECT_TRUE(eap_.IsConnectable());
150
151 // Some other non-TLS EAP type.
152 SetEap("DodgeBall");
153 EXPECT_TRUE(eap_.IsConnectable());
154
155 // EAP-TLS requires certificate parameters, and cares not for passwords.
156 SetEap("TLS");
157 EXPECT_FALSE(eap_.IsConnectable());
158
159 // Clearing the password won't help.
160 SetPassword("");
161 EXPECT_FALSE(eap_.IsConnectable());
162
163 // A client cert by itself doesn't help.
164 SetClientCert("client-cert");
165 EXPECT_FALSE(eap_.IsConnectable());
166
167 // A client cert and key will, however.
168 SetPrivateKey("client-cert");
169 EXPECT_TRUE(eap_.IsConnectable());
170
171 // A key-id (and cert) doesn't work.
172 SetKeyId("client-key-id");
173 EXPECT_FALSE(eap_.IsConnectable());
174
175 // We need a PIN for the key id in addition.
176 SetPin("pin");
177 EXPECT_TRUE(eap_.IsConnectable());
178
179 // If we clear the "EAP" property, we just assume these valid certificate
180 // credentials are the ones to be used.
181 SetEap("");
182 EXPECT_TRUE(eap_.IsConnectable());
183
184 // Check that clearing the certificate parameter breaks us again.
185 SetClientCert("");
186 EXPECT_FALSE(eap_.IsConnectable());
187
188 // Setting the cert-id will fix things.
189 SetCertId("client-cert-id");
190 EXPECT_TRUE(eap_.IsConnectable());
191}
192
193TEST_F(EapCredentialsTest, ConnectableUsingPassphrase) {
194 EXPECT_FALSE(eap_.IsConnectableUsingPassphrase());
195
196 // No password.
197 SetIdentity("TestIdentity");
198 EXPECT_FALSE(eap_.IsConnectableUsingPassphrase());
199
200 // Success.
201 SetPassword("TestPassword");
202 EXPECT_TRUE(eap_.IsConnectableUsingPassphrase());
203
204 // Clear identity.
205 SetIdentity("");
206 EXPECT_FALSE(eap_.IsConnectableUsingPassphrase());
207}
208
209TEST_F(EapCredentialsTest, IsEapAuthenticationProperty) {
210 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
211 flimflam::kEapAnonymousIdentityProperty));
212 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
213 flimflam::kEAPCertIDProperty));
214 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
215 flimflam::kEAPClientCertProperty));
216 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
217 flimflam::kEapIdentityProperty));
218 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
219 flimflam::kEAPKeyIDProperty));
220 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
221 flimflam::kEapKeyMgmtProperty));
222 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
223 flimflam::kEapPasswordProperty));
224 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
225 flimflam::kEAPPINProperty));
226 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
227 flimflam::kEapPrivateKeyProperty));
228 EXPECT_TRUE(EapCredentials::IsEapAuthenticationProperty(
229 flimflam::kEapPrivateKeyPasswordProperty));
230
231 // It's easier to test that this function returns TRUE in every situation
232 // that it should, than to test all the cases it should return FALSE in.
233 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
234 flimflam::kEapCaCertProperty));
235 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
236 flimflam::kEapCaCertIDProperty));
237 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
238 flimflam::kEapCaCertNssProperty));
239 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
240 kEapCaCertPemProperty));
241 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
242 flimflam::kEAPEAPProperty));
243 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
244 flimflam::kEapPhase2AuthProperty));
245 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
246 flimflam::kEapUseSystemCAsProperty));
247 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
248 kEapRemoteCertificationProperty));
249 EXPECT_FALSE(EapCredentials::IsEapAuthenticationProperty(
250 kEapSubjectMatchProperty));
251}
252
253TEST_F(EapCredentialsTest, LoadAndSave) {
254 MockStore store;
255 // For the values we're not testing...
256 EXPECT_CALL(store, GetCryptedString(_, _, _)).WillRepeatedly(Return(false));
257 EXPECT_CALL(store, GetString(_, _, _)).WillRepeatedly(Return(false));
258
259 const string kId("storage-id");
260 const string kIdentity("Purple Onion");
261 EXPECT_CALL(store, GetCryptedString(
262 kId, EapCredentials::kStorageEapIdentity, _))
263 .WillOnce(DoAll(SetArgumentPointee<2>(kIdentity), Return(true)));
264 const string kManagement("Shave and a Haircut");
265 EXPECT_CALL(store, GetString(
266 kId, EapCredentials::kStorageEapKeyManagement, _))
267 .WillOnce(DoAll(SetArgumentPointee<2>(kManagement), Return(true)));
268 const string kPassword("Two Bits");
269 EXPECT_CALL(store, GetCryptedString(
270 kId, EapCredentials::kStorageEapPassword, _))
271 .WillOnce(DoAll(SetArgumentPointee<2>(kPassword), Return(true)));
272
273 eap_.Load(&store, kId);
274 Mock::VerifyAndClearExpectations(&store);
275
276 EXPECT_EQ(kIdentity, eap_.identity());
277 EXPECT_EQ(kManagement, eap_.key_management());
278 EXPECT_EQ(kPassword, GetPassword());
279
280 // Authentication properties are deleted from the store if they are empty,
281 // so we expect the fields that we haven't set to be deleted.
282 EXPECT_CALL(store, DeleteKey(_, _)).Times(AnyNumber());
283 EXPECT_CALL(store, SetCryptedString(_, _, _)).Times(0);
284 EXPECT_CALL(store, DeleteKey(kId, EapCredentials::kStorageEapIdentity));
285 EXPECT_CALL(store, SetString(
286 kId, EapCredentials::kStorageEapKeyManagement, kManagement));
287 EXPECT_CALL(store, DeleteKey(kId, EapCredentials::kStorageEapPassword));
288 eap_.Save(&store, kId, false);
289 Mock::VerifyAndClearExpectations(&store);
290
291 // Authentication properties are deleted from the store if they are empty,
292 // so we expect the fields that we haven't set to be deleted.
293 EXPECT_CALL(store, DeleteKey(_, _)).Times(AnyNumber());
294 EXPECT_CALL(store, SetCryptedString(
295 kId, EapCredentials::kStorageEapIdentity, kIdentity));
296 EXPECT_CALL(store, SetString(
297 kId, EapCredentials::kStorageEapKeyManagement, kManagement));
298 EXPECT_CALL(store, SetCryptedString(
299 kId, EapCredentials::kStorageEapPassword, kPassword));
300 eap_.Save(&store, kId, true);
301}
302
303TEST_F(EapCredentialsTest, OutputConnectionMetrics) {
304 Error unused_error;
305 SetEap(flimflam::kEapMethodPEAP);
306 SetInnerEap(flimflam::kEapPhase2AuthPEAPMSCHAPV2);
307
308 MockEventDispatcher dispatcher;
309 MockMetrics metrics(&dispatcher);
310 EXPECT_CALL(metrics, SendEnumToUMA("Network.Shill.Wifi.EapOuterProtocol",
311 Metrics::kEapOuterProtocolPeap,
312 Metrics::kEapOuterProtocolMax));
313 EXPECT_CALL(metrics, SendEnumToUMA("Network.Shill.Wifi.EapInnerProtocol",
314 Metrics::kEapInnerProtocolPeapMschapv2,
315 Metrics::kEapInnerProtocolMax));
316 eap_.OutputConnectionMetrics(&metrics, Technology::kWifi);
317}
318
319TEST_F(EapCredentialsTest, PopulateSupplicantProperties) {
320 SetIdentity("testidentity");
321 SetPin("xxxx");
322 PopulateSupplicantProperties();
323 // Test that only non-empty 802.1x properties are populated.
324 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapIdentity));
325 EXPECT_FALSE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapKeyId));
326 EXPECT_FALSE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapCaCert));
327
328 // Test that CA path is set by default.
329 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyCaPath));
330
331 // Test that hardware-backed security arguments are not set, since
332 // neither key-id nor cert-id were set.
333 EXPECT_FALSE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapPin));
334 EXPECT_FALSE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEngine));
335 EXPECT_FALSE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEngineId));
336}
337
338TEST_F(EapCredentialsTest, PopulateSupplicantPropertiesNoSystemCAs) {
339 SetIdentity("testidentity");
340 SetUseSystemCAs(false);
341 PopulateSupplicantProperties();
342 // Test that CA path is not set if use_system_cas is explicitly false.
343 EXPECT_FALSE(ContainsKey(params_, WPASupplicant::kNetworkPropertyCaPath));
344}
345
346TEST_F(EapCredentialsTest, PopulateSupplicantPropertiesUsingHardwareAuth) {
347 SetIdentity("testidentity");
348 SetKeyId("key_id");
349 SetPin("xxxx");
350 PopulateSupplicantProperties();
351 // Test that EAP engine parameters set if key_id is set.
352 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapPin));
353 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapKeyId));
354 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEngine));
355 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEngineId));
356}
357
358TEST_F(EapCredentialsTest, PopulateSupplicantPropertiesNSS) {
359 const string kNSSNickname("nss_nickname");
360 SetCACertNSS(kNSSNickname);
361 const string kNSSCertfile("/tmp/nss-cert");
362 FilePath nss_cert(kNSSCertfile);
363 nss_identifier_ = vector<char>(1, 'a');
364 EXPECT_CALL(nss_, GetDERCertfile(kNSSNickname, nss_identifier_))
365 .WillOnce(Return(nss_cert));
366 PopulateSupplicantProperties();
367 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapCaCert));
368 if (ContainsKey(params_, WPASupplicant::kNetworkPropertyEapCaCert)) {
369 EXPECT_EQ(kNSSCertfile, params_[WPASupplicant::kNetworkPropertyEapCaCert]
370 .reader().get_string());
371 }
372}
373
374TEST_F(EapCredentialsTest, PopulateSupplicantPropertiesPEM) {
375 const string kPemCert("-pem-certificate-here-");
376 SetCACertPEM(kPemCert);
377 const string kPEMCertfile("/tmp/pem-cert");
378 FilePath pem_cert(kPEMCertfile);
379 EXPECT_CALL(certificate_file_, CreateDERFromString(kPemCert))
380 .WillOnce(Return(pem_cert));
381
382 PopulateSupplicantProperties();
383 EXPECT_TRUE(ContainsKey(params_, WPASupplicant::kNetworkPropertyEapCaCert));
384 if (ContainsKey(params_, WPASupplicant::kNetworkPropertyEapCaCert)) {
385 EXPECT_EQ(kPEMCertfile, params_[WPASupplicant::kNetworkPropertyEapCaCert]
386 .reader().get_string());
387 }
388}
389
390TEST_F(EapCredentialsTest, PopulateWiMaxProperties) {
391 {
392 KeyValueStore parameters;
393 eap_.PopulateWiMaxProperties(&parameters);
394
395 EXPECT_FALSE(parameters.ContainsString(
396 wimax_manager::kEAPAnonymousIdentity));
397 EXPECT_FALSE(parameters.ContainsString(
398 wimax_manager::kEAPUserIdentity));
399 EXPECT_FALSE(parameters.ContainsString(
400 wimax_manager::kEAPUserPassword));
401 }
402
403 const string kAnonymousIdentity("TestAnonymousIdentity");
404 SetAnonymousIdentity(kAnonymousIdentity);
405 const string kIdentity("TestUserIdentity");
406 SetIdentity(kIdentity);
407 const string kPassword("TestPassword");
408 SetPassword(kPassword);
409
410 {
411 KeyValueStore parameters;
412 eap_.PopulateWiMaxProperties(&parameters);
413 EXPECT_EQ(kAnonymousIdentity, parameters.LookupString(
414 wimax_manager::kEAPAnonymousIdentity, ""));
415 EXPECT_EQ(kIdentity, parameters.LookupString(
416 wimax_manager::kEAPUserIdentity, ""));
417 EXPECT_EQ(kPassword, parameters.LookupString(
418 wimax_manager::kEAPUserPassword, ""));
419 }
420}
421
422TEST_F(EapCredentialsTest, Reset) {
423 EXPECT_TRUE(IsReset());
Paul Stewart9956dc72013-04-23 14:06:17 -0700424 EXPECT_TRUE(GetKeyManagement().empty());
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700425 SetAnonymousIdentity("foo");
426 SetCACertNSS("foo");
427 SetCACertPEM("foo");
428 SetClientCert("foo");
429 SetCertId("foo");
430 SetEap("foo");
431 SetIdentity("foo");
432 SetInnerEap("foo");
433 SetKeyId("foo");
434 SetPassword("foo");
435 SetPrivateKey("foo");
436 SetPin("foo");
437 SetUseSystemCAs(false);
Paul Stewart9956dc72013-04-23 14:06:17 -0700438 eap_.SetKeyManagement("foo", NULL);
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700439 EXPECT_FALSE(IsReset());
Paul Stewart9956dc72013-04-23 14:06:17 -0700440 EXPECT_FALSE(GetKeyManagement().empty());
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700441 eap_.Reset();
442 EXPECT_TRUE(IsReset());
Paul Stewart9956dc72013-04-23 14:06:17 -0700443 EXPECT_FALSE(GetKeyManagement().empty());
444}
445
446TEST_F(EapCredentialsTest, SetKeyManagement) {
447 const string kKeyManagement0("foo");
448 eap_.SetKeyManagement(kKeyManagement0, NULL);
449 EXPECT_EQ(kKeyManagement0, GetKeyManagement());
450
451 const string kKeyManagement1("bar");
452 eap_.SetKeyManagement(kKeyManagement1, NULL);
453 EXPECT_EQ(kKeyManagement1, GetKeyManagement());
454
455 // We should not be able to set the key management to an empty string.
456 eap_.SetKeyManagement("", NULL);
457 EXPECT_EQ(kKeyManagement1, GetKeyManagement());
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700458}
459
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700460// Custom property setters should return false, and make no changes, if
461// the new value is the same as the old value.
462TEST_F(EapCredentialsTest, CustomSetterNoopChange) {
463 // SetEapKeyManagement
464 {
465 const string kKeyManagement("foo");
466 Error error;
467 // Set to known value.
468 EXPECT_TRUE(eap_.SetKeyManagement(kKeyManagement, &error));
469 EXPECT_TRUE(error.IsSuccess());
470 // Set to same value.
471 EXPECT_FALSE(eap_.SetKeyManagement(kKeyManagement, &error));
472 EXPECT_TRUE(error.IsSuccess());
473 }
474
475 // SetEapPassword
476 {
477 const string kPassword("foo");
478 Error error;
479 // Set to known value.
480 EXPECT_TRUE(SetEapPassword(kPassword, &error));
481 EXPECT_TRUE(error.IsSuccess());
482 // Set to same value.
483 EXPECT_FALSE(SetEapPassword(kPassword, &error));
484 EXPECT_TRUE(error.IsSuccess());
485 }
486
487 // SetEapPrivateKeyPassword
488 {
489 const string kPrivateKeyPassword("foo");
490 Error error;
491 // Set to known value.
492 EXPECT_TRUE(SetEapPrivateKeyPassword(kPrivateKeyPassword, &error));
493 EXPECT_TRUE(error.IsSuccess());
494 // Set to same value.
495 EXPECT_FALSE(SetEapPrivateKeyPassword(kPrivateKeyPassword, &error));
496 EXPECT_TRUE(error.IsSuccess());
497 }
498}
499
Paul Stewartc43cbbe2013-04-11 06:29:30 -0700500} // namespace shill