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 5import logging 6import os 7import random 8import stat 9import string 10import sys 11import tempfile 12 13from autotest_lib.client.common_lib import error 14from autotest_lib.client.common_lib.cros import xmlrpc_types 15 16 17def deserialize(serialized): 18 """Deserialize a SecurityConfig. 19 20 @param serialized dict representing a serialized SecurityConfig. 21 @return a SecurityConfig object built from |serialized|. 22 23 """ 24 return xmlrpc_types.deserialize(serialized, module=sys.modules[__name__]) 25 26 27class SecurityConfig(xmlrpc_types.XmlRpcStruct): 28 """Abstracts the security configuration for a WiFi network. 29 30 This bundle of credentials can be passed to both HostapConfig and 31 AssociationParameters so that both shill and hostapd can set up and connect 32 to an encrypted WiFi network. By default, we'll assume we're connecting 33 to an open network. 34 35 """ 36 SERVICE_PROPERTY_PASSPHRASE = 'Passphrase' 37 38 def __init__(self, security='none'): 39 super(SecurityConfig, self).__init__() 40 self.security = security 41 42 43 def get_hostapd_config(self): 44 """@return dict fragment of hostapd configuration for security.""" 45 return {} 46 47 48 def get_shill_service_properties(self): 49 """@return dict of shill service properties.""" 50 return {} 51 52 53 def get_wpa_cli_properties(self): 54 """@return dict values to be set with wpa_cli set_network.""" 55 return {'key_mgmt': 'NONE'} 56 57 58 def install_router_credentials(self, host): 59 """Install the necessary credentials on the router. 60 61 @param host host object representing the router. 62 63 """ 64 pass # Many authentication methods have no special router credentials. 65 66 67 def install_client_credentials(self, tpm_store): 68 """Install credentials on the local host (hopefully a DUT). 69 70 Only call this if we're running on a DUT in a WiFi test. This 71 method can do things like install credentials into the TPM. 72 73 @param tpm_store TPMStore object representing the TPM on our DUT. 74 75 """ 76 pass # Many authentication methods have no special client credentials. 77 78 79 def __repr__(self): 80 return '%s(%s)' % (self.__class__.__name__, 81 ', '.join(['%s=%r' % item 82 for item in vars(self).iteritems()])) 83 84 85class WEPConfig(SecurityConfig): 86 """Abstracts security configuration for a WiFi network using static WEP.""" 87 # Open system authentication means that we don't do a 4 way AUTH handshake, 88 # and simply start using the WEP keys after association finishes. 89 AUTH_ALGORITHM_OPEN = 1 90 # This refers to a mode where the AP sends a plaintext challenge and the 91 # client sends back the challenge encrypted with the WEP key as part of a 4 92 # part auth handshake. 93 AUTH_ALGORITHM_SHARED = 2 94 AUTH_ALGORITHM_DEFAULT = AUTH_ALGORITHM_OPEN 95 96 @staticmethod 97 def _format_key(key, ascii_key_formatter): 98 """Returns a key formatted to for its appropriate consumer. 99 100 Both hostapd and wpa_cli want their ASCII encoded WEP keys formatted 101 in a particular way. Hex string on the other hand can be given raw. 102 Other key formats aren't even accepted, and this method will raise 103 and exception if it sees such a key. 104 105 @param key string a 40/104 bit WEP key. 106 @param ascii_key_formatter converter function that escapes a WEP 107 string-encoded passphrase. This conversion varies in format 108 depending on the consumer. 109 @return string corrected formatted WEP key. 110 111 """ 112 if len(key) in (5, 13): 113 # These are 'ASCII' strings, or at least N-byte strings 114 # of the right size. 115 return ascii_key_formatter(key) 116 117 if len(key) in (10, 26): 118 # These are hex encoded byte strings. 119 return key 120 121 raise error.TestFail('Invalid WEP key: %r' % key) 122 123 124 def __init__(self, wep_keys, wep_default_key=0, 125 auth_algorithm=AUTH_ALGORITHM_DEFAULT): 126 """Construct a WEPConfig object. 127 128 @param wep_keys list of string WEP keys. 129 @param wep_default_key int 0 based index into |wep_keys| for the default 130 key. 131 @param auth_algorithm int bitfield of AUTH_ALGORITHM_* defined above. 132 133 """ 134 super(WEPConfig, self).__init__(security='wep') 135 self.wep_keys = wep_keys 136 self.wep_default_key = wep_default_key 137 self.auth_algorithm = auth_algorithm 138 if self.auth_algorithm & ~(self.AUTH_ALGORITHM_OPEN | 139 self.AUTH_ALGORITHM_SHARED): 140 raise error.TestFail('Invalid authentication mode specified (%d).' % 141 self.auth_algorithm) 142 143 if self.wep_keys and len(self.wep_keys) > 4: 144 raise error.TestFail('More than 4 WEP keys specified (%d).' % 145 len(self.wep_keys)) 146 147 148 def get_hostapd_config(self): 149 """@return dict fragment of hostapd configuration for security.""" 150 ret = {} 151 quote = lambda x: '"%s"' % x 152 for idx,key in enumerate(self.wep_keys): 153 ret['wep_key%d' % idx] = self._format_key(key, quote) 154 ret['wep_default_key'] = self.wep_default_key 155 ret['auth_algs'] = self.auth_algorithm 156 return ret 157 158 159 def get_shill_service_properties(self): 160 """@return dict of shill service properties.""" 161 return {self.SERVICE_PROPERTY_PASSPHRASE: '%d:%s' % ( 162 self.wep_default_key, 163 self.wep_keys[self.wep_default_key])} 164 165 166 def get_wpa_cli_properties(self): 167 properties = super(WEPConfig, self).get_wpa_cli_properties() 168 quote = lambda x: '\\"%s\\"' % x 169 for idx, key in enumerate(self.wep_keys): 170 properties['wep_key%d' % idx] = self._format_key(key, quote) 171 properties['wep_tx_keyidx'] = self.wep_default_key 172 if self.auth_algorithm == self.AUTH_ALGORITHM_SHARED: 173 properties['auth_alg'] = 'SHARED' 174 return properties 175 176 177class WPAConfig(SecurityConfig): 178 """Abstracts security configuration for a WPA encrypted WiFi network.""" 179 180 # We have the option of turning on WPA, WPA2, or both via a bitfield. 181 MODE_PURE_WPA = 1 182 MODE_PURE_WPA2 = 2 183 MODE_MIXED_WPA = MODE_PURE_WPA | MODE_PURE_WPA2 184 MODE_DEFAULT = MODE_MIXED_WPA 185 186 # WPA2 mandates the use of AES in CCMP mode. 187 # WPA allows the use of 'ordinary' AES, but mandates support for TKIP. 188 # The protocol however seems to indicate that you just list a bunch of 189 # different ciphers that you support and we'll start speaking one. 190 CIPHER_CCMP = 'CCMP' 191 CIPHER_TKIP = 'TKIP' 192 193 def __init__(self, psk='', wpa_mode=MODE_DEFAULT, wpa_ciphers=[], 194 wpa2_ciphers=[], wpa_ptk_rekey_period=None, 195 wpa_gtk_rekey_period=None, wpa_gmk_rekey_period=None, 196 use_strict_rekey=None): 197 """Construct a WPAConfig. 198 199 @param psk string a passphrase (64 hex characters or an ASCII phrase up 200 to 63 characters long). 201 @param wpa_mode int one of MODE_* above. 202 @param wpa_ciphers list of ciphers to advertise in the WPA IE. 203 @param wpa2_ciphers list of ciphers to advertise in the WPA2 IE. 204 hostapd will fall back on WPA ciphers for WPA2 if this is 205 left unpopulated. 206 @param wpa_ptk_rekey_period int number of seconds between PTK rekeys. 207 @param wpa_gtk_rekey_period int number of second between GTK rekeys. 208 @param wpa_gmk_rekey_period int number of seconds between GMK rekeys. 209 The GMK is a key internal to hostapd used to generate GTK. 210 It is the 'master' key. 211 @param use_strict_rekey bool True iff hostapd should refresh the GTK 212 whenever any client leaves the group. 213 214 """ 215 super(WPAConfig, self).__init__(security='psk') 216 self.psk = psk 217 self.wpa_mode = wpa_mode 218 self.wpa_ciphers = wpa_ciphers 219 self.wpa2_ciphers = wpa2_ciphers 220 self.wpa_ptk_rekey_period = wpa_ptk_rekey_period 221 self.wpa_gtk_rekey_period = wpa_gtk_rekey_period 222 self.wpa_gmk_rekey_period = wpa_gmk_rekey_period 223 self.use_strict_rekey = use_strict_rekey 224 if len(psk) > 64: 225 raise error.TestFail('WPA passphrases can be no longer than 63 ' 226 'characters (or 64 hex digits).') 227 228 if len(psk) == 64: 229 for c in psk: 230 if c not in '0123456789abcdefABCDEF': 231 raise error.TestFail('Invalid PMK: %r' % psk) 232 233 234 def get_hostapd_config(self): 235 """@return dict fragment of hostapd configuration for security.""" 236 if not self.wpa_mode: 237 raise error.TestFail('Cannot configure WPA unless we know which ' 238 'mode to use.') 239 240 if self.MODE_PURE_WPA & self.wpa_mode and not self.wpa_ciphers: 241 raise error.TestFail('Cannot configure WPA unless we know which ' 242 'ciphers to use.') 243 244 if not self.wpa_ciphers and not self.wpa2_ciphers: 245 raise error.TestFail('Cannot configure WPA2 unless we have some ' 246 'ciphers.') 247 248 ret = {'wpa': self.wpa_mode, 249 'wpa_key_mgmt': 'WPA-PSK'} 250 if len(self.psk) == 64: 251 ret['wpa_psk'] = self.psk 252 else: 253 ret['wpa_passphrase'] = self.psk 254 255 if self.wpa_ciphers: 256 ret['wpa_pairwise'] = ' '.join(self.wpa_ciphers) 257 if self.wpa2_ciphers: 258 ret['rsn_pairwise'] = ' '.join(self.wpa2_ciphers) 259 if self.wpa_ptk_rekey_period: 260 ret['wpa_ptk_rekey'] = self.wpa_ptk_rekey_period 261 if self.wpa_gtk_rekey_period: 262 ret['wpa_group_rekey'] = self.wpa_gtk_rekey_period 263 if self.wpa_gmk_rekey_period: 264 ret['wpa_gmk_rekey'] = self.wpa_gmk_rekey_period 265 if self.use_strict_rekey: 266 ret['wpa_strict_rekey'] = 1 267 return ret 268 269 270 def get_shill_service_properties(self): 271 """@return dict of shill service properties.""" 272 return {self.SERVICE_PROPERTY_PASSPHRASE: self.psk} 273 274 275 def get_wpa_cli_properties(self): 276 properties = super(WPAConfig, self).get_wpa_cli_properties() 277 # TODO(wiley) This probably doesn't work for raw PMK. 278 protos = [] 279 if self.wpa_mode & self.MODE_PURE_WPA: 280 protos.append('WPA') 281 if self.wpa_mode & self.MODE_PURE_WPA2: 282 protos.append('RSN') 283 properties.update({'psk': '\\"%s\\"' % self.psk, 284 'key_mgmt': 'WPA-PSK', 285 'proto': ' '.join(protos)}) 286 return properties 287 288 289class EAPConfig(SecurityConfig): 290 """Abstract superclass that implements certificate/key installation.""" 291 292 DEFAULT_EAP_USERS = '* TLS' 293 DEFAULT_EAP_IDENTITY = 'chromeos' 294 295 SERVICE_PROPERTY_CA_CERT_PEM = 'EAP.CACertPEM' 296 SERVICE_PROPERTY_CLIENT_CERT_ID = 'EAP.CertID' 297 SERVICE_PROPERTY_EAP_IDENTITY = 'EAP.Identity' 298 SERVICE_PROPERTY_EAP_KEY_MGMT = 'EAP.KeyMgmt' 299 SERVICE_PROPERTY_EAP_PASSWORD = 'EAP.Password' 300 SERVICE_PROPERTY_EAP_PIN = 'EAP.PIN' 301 SERVICE_PROPERTY_INNER_EAP= 'EAP.InnerEAP' 302 SERVICE_PROPERTY_PRIVATE_KEY_ID = 'EAP.KeyID' 303 SERVICE_PROPERTY_USE_SYSTEM_CAS = 'EAP.UseSystemCAs' 304 305 last_tpm_id = 8800 306 307 308 @staticmethod 309 def reserve_TPM_id(): 310 """@return session unique TPM identifier.""" 311 ret = str(EAPConfig.last_tpm_id) 312 EAPConfig.last_tpm_id += 1 313 return ret 314 315 316 def __init__(self, security='802_1x', file_suffix=None, use_system_cas=None, 317 server_ca_cert=None, server_cert=None, server_key=None, 318 server_eap_users=None, 319 client_ca_cert=None, client_cert=None, client_key=None, 320 client_cert_id=None, client_key_id=None, 321 eap_identity=None): 322 """Construct an EAPConfig. 323 324 @param file_suffix string unique file suffix on DUT. 325 @param use_system_cas False iff we should ignore server certificates. 326 @param server_ca_cert string PEM encoded CA certificate for the server. 327 @param server_cert string PEM encoded identity certificate for server. 328 @param server_key string PEM encoded private key for server. 329 @param server_eap_users string contents of EAP user file. 330 @param client_ca_cert string PEM encoded CA certificate for client. 331 @param client_cert string PEM encoded identity certificate for client. 332 @param client_key string PEM encoded private key for client. 333 @param client_cert_id string identifier for client certificate in TPM. 334 @param client_key_id string identifier for client private key in TPM. 335 @param eap_identity string user to authenticate as during EAP. 336 337 """ 338 super(EAPConfig, self).__init__(security=security) 339 self.use_system_cas = use_system_cas 340 self.server_ca_cert = server_ca_cert 341 self.server_cert = server_cert 342 self.server_key = server_key 343 self.server_eap_users = server_eap_users or self.DEFAULT_EAP_USERS 344 self.client_ca_cert = client_ca_cert 345 self.client_cert = client_cert 346 self.client_key = client_key 347 if file_suffix is None: 348 suffix_letters = string.ascii_lowercase + string.digits 349 file_suffix = ''.join(random.choice(suffix_letters) 350 for x in range(10)) 351 logging.debug('Choosing unique file_suffix %s.', file_suffix) 352 self.server_ca_cert_file = '/tmp/hostapd_ca_cert_file.' + file_suffix 353 self.server_cert_file = '/tmp/hostapd_cert_file.' + file_suffix 354 self.server_key_file = '/tmp/hostapd_key_file.' + file_suffix 355 self.server_eap_user_file = '/tmp/hostapd_eap_user_file.' + file_suffix 356 # While these paths won't make it across the network, the suffix will. 357 self.file_suffix = file_suffix 358 self.client_cert_id = client_cert_id or self.reserve_TPM_id() 359 self.client_key_id = client_key_id or self.reserve_TPM_id() 360 # This gets filled in at install time. 361 self.pin = None 362 # The slot where the certificate/key are installed in the TPM. 363 self.client_cert_slot_id = None 364 self.client_key_slot_id = None 365 self.eap_identity = eap_identity or self.DEFAULT_EAP_IDENTITY 366 367 368 def install_router_credentials(self, host): 369 """Install the necessary credentials on the router. 370 371 @param host host object representing the router. 372 373 """ 374 files = [(self.server_ca_cert, self.server_ca_cert_file), 375 (self.server_cert, self.server_cert_file), 376 (self.server_key, self.server_key_file), 377 (self.server_eap_users, self.server_eap_user_file)] 378 for content, path in files: 379 # If we omit a parameter, just omit copying a file over. 380 if content is None: 381 continue 382 # Write the contents to local disk first so we can use the easy 383 # built in mechanism to do this. 384 with tempfile.NamedTemporaryFile() as f: 385 f.write(content) 386 f.flush() 387 os.chmod(f.name, stat.S_IRUSR | stat.S_IWUSR | 388 stat.S_IRGRP | stat.S_IWGRP | 389 stat.S_IROTH | stat.S_IWOTH) 390 host.send_file(f.name, path, delete_dest=True) 391 392 393 def install_client_credentials(self, tpm_store): 394 """Install credentials on the local host (hopefully a DUT). 395 396 Only call this if we're running on a DUT in a WiFi test. This 397 method can do things like install credentials into the TPM. 398 399 @param tpm_store TPMStore object representing the TPM on our DUT. 400 401 """ 402 if self.client_cert: 403 tpm_store.install_certificate(self.client_cert, self.client_cert_id) 404 self.client_cert_slot_id = tpm_store.SLOT_ID 405 self.pin = tpm_store.PIN 406 if self.client_key: 407 tpm_store.install_private_key(self.client_key, self.client_key_id) 408 self.client_key_slot_id = tpm_store.SLOT_ID 409 self.pin = tpm_store.PIN 410 411 412 def get_shill_service_properties(self): 413 """@return dict of shill service properties.""" 414 ret = {self.SERVICE_PROPERTY_EAP_IDENTITY: self.eap_identity} 415 if self.pin: 416 ret[self.SERVICE_PROPERTY_EAP_PIN] = self.pin 417 if self.client_ca_cert: 418 # Technically, we could accept a list of certificates here, but we 419 # have no such tests. 420 ret[self.SERVICE_PROPERTY_CA_CERT_PEM] = [self.client_ca_cert] 421 if self.client_cert: 422 ret[self.SERVICE_PROPERTY_CLIENT_CERT_ID] = ( 423 '%s:%s' % (self.client_cert_slot_id, self.client_cert_id)) 424 if self.client_key: 425 ret[self.SERVICE_PROPERTY_PRIVATE_KEY_ID] = ( 426 '%s:%s' % (self.client_key_slot_id, self.client_key_id)) 427 if self.use_system_cas is not None: 428 ret[self.SERVICE_PROPERTY_USE_SYSTEM_CAS] = self.use_system_cas 429 return ret 430 431 432 def get_hostapd_config(self): 433 """@return dict fragment of hostapd configuration for security.""" 434 return {'ieee8021x': 1, # Enable 802.1x support. 435 'eap_server' : 1, # Do EAP inside hostapd to avoid RADIUS. 436 'ca_cert': self.server_ca_cert_file, 437 'server_cert': self.server_cert_file, 438 'private_key': self.server_key_file, 439 'eap_user_file': self.server_eap_user_file} 440 441 442class DynamicWEPConfig(EAPConfig): 443 """Configuration settings bundle for dynamic WEP. 444 445 This is a WEP encrypted connection where the keys are negotiated after the 446 client authenticates via 802.1x. 447 448 """ 449 450 DEFAULT_REKEY_PERIOD = 20 451 452 453 def __init__(self, use_short_keys=False, 454 wep_rekey_period=DEFAULT_REKEY_PERIOD, 455 server_ca_cert=None, server_cert=None, server_key=None, 456 client_ca_cert=None, client_cert=None, client_key=None, 457 file_suffix=None, client_cert_id=None, client_key_id=None): 458 """Construct a DynamicWEPConfig. 459 460 @param use_short_keys bool force hostapd to use 40 bit WEP keys. 461 @param wep_rekey_period int number of second between rekeys. 462 @param server_ca_cert string PEM encoded CA certificate for the server. 463 @param server_cert string PEM encoded identity certificate for server. 464 @param server_key string PEM encoded private key for server. 465 @param client_ca_cert string PEM encoded CA certificate for client. 466 @param client_cert string PEM encoded identity certificate for client. 467 @param client_key string PEM encoded private key for client. 468 @param file_suffix string unique file suffix on DUT. 469 @param client_cert_id string identifier for client certificate in TPM. 470 @param client_key_id string identifier for client private key in TPM. 471 472 """ 473 super(DynamicWEPConfig, self).__init__( 474 security='wep', file_suffix=file_suffix, 475 server_ca_cert=server_ca_cert, server_cert=server_cert, 476 server_key=server_key, client_ca_cert=client_ca_cert, 477 client_cert=client_cert, client_key=client_key, 478 client_cert_id=client_cert_id, client_key_id=client_key_id) 479 self.use_short_keys = use_short_keys 480 self.wep_rekey_period = wep_rekey_period 481 482 483 def get_hostapd_config(self): 484 """@return dict fragment of hostapd configuration for security.""" 485 ret = super(DynamicWEPConfig, self).get_hostapd_config() 486 key_len = 13 # 128 bit WEP, 104 secret bits. 487 if self.use_short_keys: 488 key_len = 5 # 64 bit WEP, 40 bits of secret. 489 ret.update({'wep_key_len_broadcast': key_len, 490 'wep_key_len_unicast': key_len, 491 'wep_rekey_period': self.wep_rekey_period}) 492 return ret 493 494 495 def get_shill_service_properties(self): 496 """@return dict of shill service properties.""" 497 ret = super(DynamicWEPConfig, self).get_shill_service_properties() 498 ret.update({self.SERVICE_PROPERTY_EAP_KEY_MGMT: 'IEEE8021X'}) 499 return ret 500 501 502class WPAEAPConfig(EAPConfig): 503 """Security type to set up a WPA tunnel via EAP-TLS negotiation.""" 504 505 def __init__(self, file_suffix=None, use_system_cas=None, 506 server_ca_cert=None, server_cert=None, server_key=None, 507 client_ca_cert=None, client_cert=None, client_key=None, 508 client_cert_id=None, client_key_id=None, 509 eap_identity=None, server_eap_users=None, 510 wpa_mode=WPAConfig.MODE_PURE_WPA): 511 """Construct a DynamicWEPConfig. 512 513 @param file_suffix string unique file suffix on DUT. 514 @param use_system_cas False iff we should ignore server certificates. 515 @param server_ca_cert string PEM encoded CA certificate for the server. 516 @param server_cert string PEM encoded identity certificate for server. 517 @param server_key string PEM encoded private key for server. 518 @param client_ca_cert string PEM encoded CA certificate for client. 519 @param client_cert string PEM encoded identity certificate for client. 520 @param client_key string PEM encoded private key for client. 521 @param client_cert_id string identifier for client certificate in TPM. 522 @param client_key_id string identifier for client private key in TPM. 523 @param eap_identity string user to authenticate as during EAP. 524 @param server_eap_users string contents of server EAP users file. 525 526 """ 527 super(WPAEAPConfig, self).__init__( 528 file_suffix=file_suffix, use_system_cas=use_system_cas, 529 server_ca_cert=server_ca_cert, server_cert=server_cert, 530 server_key=server_key, client_ca_cert=client_ca_cert, 531 client_cert=client_cert, client_key=client_key, 532 client_cert_id=client_cert_id, client_key_id=client_key_id, 533 eap_identity=eap_identity, server_eap_users=server_eap_users) 534 self.wpa_mode = wpa_mode 535 536 537 def get_hostapd_config(self): 538 """@return dict fragment of hostapd configuration for security.""" 539 ret = super(WPAEAPConfig, self).get_hostapd_config() 540 # If we wanted to expand test coverage to WPA2/PEAP combinations 541 # or particular ciphers, we'd have to let people set these 542 # settings manually. But for now, do the simple thing. 543 ret.update({'wpa': self.wpa_mode, 544 'wpa_pairwise': WPAConfig.CIPHER_CCMP, 545 'wpa_key_mgmt':'WPA-EAP'}) 546 return ret 547 548 549class Tunneled1xConfig(WPAEAPConfig): 550 """Security type to set up a TTLS/PEAP connection. 551 552 Both PEAP and TTLS are tunneled protocols which use EAP inside of a TLS 553 secured tunnel. The secured tunnel is a symmetric key encryption scheme 554 negotiated under the protection of a public key in the server certificate. 555 Thus, we'll see server credentials in the form of certificates, but client 556 credentials in the form of passwords and a CA Cert to root the trust chain. 557 558 """ 559 560 TTLS_PREFIX = 'TTLS-' 561 562 LAYER1_TYPE_PEAP = 'PEAP' 563 LAYER1_TYPE_TTLS = 'TTLS' 564 565 LAYER2_TYPE_GTC = 'GTC' 566 LAYER2_TYPE_MSCHAPV2 = 'MSCHAPV2' 567 LAYER2_TYPE_MD5 = 'MD5' 568 LAYER2_TYPE_TTLS_MSCHAPV2 = TTLS_PREFIX + 'MSCHAPV2' 569 LAYER2_TYPE_TTLS_MSCHAP = TTLS_PREFIX + 'MSCHAP' 570 LAYER2_TYPE_TTLS_PAP = TTLS_PREFIX + 'PAP' 571 572 def __init__(self, server_ca_cert, server_cert, server_key, 573 client_ca_cert, eap_identity, password, 574 outer_protocol=LAYER1_TYPE_PEAP, 575 inner_protocol=LAYER2_TYPE_MD5, 576 client_password=None, file_suffix=None): 577 self.password = password 578 if client_password is not None: 579 # Override the password used on the client. This lets us set 580 # bad passwords for testing. However, we use the real password 581 # below for the server config. 582 self.password = client_password 583 self.inner_protocol = inner_protocol 584 # hostapd wants these surrounded in double quotes. 585 quote = lambda x: '"' + x + '"' 586 eap_users = map(' '.join, [('*', outer_protocol), 587 (quote(eap_identity), inner_protocol, 588 quote(password), '[2]')]) 589 super(Tunneled1xConfig, self).__init__( 590 server_ca_cert=server_ca_cert, 591 server_cert=server_cert, 592 server_key=server_key, 593 server_eap_users='\n'.join(eap_users), 594 client_ca_cert=client_ca_cert, 595 eap_identity=eap_identity, 596 file_suffix=file_suffix) 597 598 599 def get_shill_service_properties(self): 600 """@return dict of shill service properties.""" 601 ret = super(Tunneled1xConfig, self).get_shill_service_properties() 602 ret.update({self.SERVICE_PROPERTY_EAP_PASSWORD: self.password}) 603 if self.inner_protocol.startswith(self.TTLS_PREFIX): 604 auth_str = 'auth=' + self.inner_protocol[len(self.TTLS_PREFIX):] 605 ret.update({self.SERVICE_PROPERTY_INNER_EAP: auth_str}) 606 return ret 607