1#   Copyright 2017 - The Android Open Source Project
2#
3#   Licensed under the Apache License, Version 2.0 (the "License");
4#   you may not use this file except in compliance with the License.
5#   You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#   Unless required by applicable law or agreed to in writing, software
10#   distributed under the License is distributed on an "AS IS" BASIS,
11#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#   See the License for the specific language governing permissions and
13#   limitations under the License.
14
15import collections
16import string
17
18from acts.controllers.ap_lib import hostapd_constants
19
20
21class Security(object):
22    """The Security class for hostapd representing some of the security
23       settings that are allowed in hostapd.  If needed more can be added.
24    """
25    def __init__(self,
26                 security_mode=None,
27                 password=None,
28                 wpa_cipher=hostapd_constants.WPA_DEFAULT_CIPHER,
29                 wpa2_cipher=hostapd_constants.WPA2_DEFAULT_CIPER,
30                 wpa_group_rekey=hostapd_constants.WPA_GROUP_KEY_ROTATION_TIME,
31                 wpa_strict_rekey=hostapd_constants.WPA_STRICT_REKEY_DEFAULT,
32                 wep_default_key=hostapd_constants.WEP_DEFAULT_KEY,
33                 radius_server_ip=None,
34                 radius_server_port=None,
35                 radius_server_secret=None):
36        """Gather all of the security settings for WPA-PSK.  This could be
37           expanded later.
38
39        Args:
40            security_mode: Type of security modes.
41                           Options: wep, wpa, wpa2, wpa/wpa2, wpa3
42            password: The PSK or passphrase for the security mode.
43            wpa_cipher: The cipher to be used for wpa.
44                        Options: TKIP, CCMP, TKIP CCMP
45                        Default: TKIP
46            wpa2_cipher: The cipher to be used for wpa2.
47                         Options: TKIP, CCMP, TKIP CCMP
48                         Default: CCMP
49            wpa_group_rekey: How often to refresh the GTK regardless of network
50                             changes.
51                             Options: An integrer in seconds, None
52                             Default: 600 seconds
53            wpa_strict_rekey: Whether to do a group key update when client
54                              leaves the network or not.
55                              Options: True, False
56                              Default: True
57            wep_default_key: The wep key number to use when transmitting.
58            radius_server_ip: Radius server IP for Enterprise auth.
59            radius_server_port: Radius server port for Enterprise auth.
60            radius_server_secret: Radius server secret for Enterprise auth.
61        """
62        self.wpa_cipher = wpa_cipher
63        self.wpa2_cipher = wpa2_cipher
64        self.wpa3 = security_mode == hostapd_constants.WPA3_STRING
65        self.wpa_group_rekey = wpa_group_rekey
66        self.wpa_strict_rekey = wpa_strict_rekey
67        self.wep_default_key = wep_default_key
68        self.radius_server_ip = radius_server_ip
69        self.radius_server_port = radius_server_port
70        self.radius_server_secret = radius_server_secret
71        if security_mode == hostapd_constants.WPA_STRING:
72            security_mode = hostapd_constants.WPA1
73        # Both wpa2 and wpa3 use hostapd security mode 2, and are distinguished
74        # by their key management field (WPA-PSK and SAE, respectively)
75        elif (security_mode == hostapd_constants.WPA2_STRING
76              or security_mode == hostapd_constants.WPA3_STRING):
77            security_mode = hostapd_constants.WPA2
78        elif security_mode == hostapd_constants.WPA_MIXED_STRING:
79            security_mode = hostapd_constants.MIXED
80        elif security_mode == hostapd_constants.WEP_STRING:
81            security_mode = hostapd_constants.WEP
82        elif security_mode == hostapd_constants.ENT_STRING:
83            security_mode = hostapd_constants.ENT
84        else:
85            security_mode = None
86        self.security_mode = security_mode
87        if password:
88            if security_mode == hostapd_constants.WEP:
89                if len(password) in hostapd_constants.WEP_STR_LENGTH:
90                    self.password = '"%s"' % password
91                elif len(password) in hostapd_constants.WEP_HEX_LENGTH and all(
92                        c in string.hexdigits for c in password):
93                    self.password = password
94                else:
95                    raise ValueError(
96                        'WEP key must be a hex string of %s characters' %
97                        hostapd_constants.WEP_HEX_LENGTH)
98            else:
99                if len(password) < hostapd_constants.MIN_WPA_PSK_LENGTH or len(
100                        password) > hostapd_constants.MAX_WPA_PSK_LENGTH:
101                    raise ValueError(
102                        'Password must be a minumum of %s characters and a maximum of %s'
103                        % (hostapd_constants.MIN_WPA_PSK_LENGTH,
104                           hostapd_constants.MAX_WPA_PSK_LENGTH))
105                else:
106                    self.password = password
107
108    def generate_dict(self):
109        """Returns: an ordered dictionary of settings"""
110        settings = collections.OrderedDict()
111        if self.security_mode is not None:
112            if self.security_mode == hostapd_constants.WEP:
113                settings['wep_default_key'] = self.wep_default_key
114                settings['wep_key' + str(self.wep_default_key)] = self.password
115            elif self.security_mode == hostapd_constants.ENT:
116                settings['auth_server_addr'] = self.radius_server_ip
117                settings['auth_server_port'] = self.radius_server_port
118                settings[
119                    'auth_server_shared_secret'] = self.radius_server_secret
120                settings['wpa_key_mgmt'] = hostapd_constants.ENT_KEY_MGMT
121                settings['ieee8021x'] = hostapd_constants.IEEE8021X
122                settings['wpa'] = hostapd_constants.WPA2
123            else:
124                settings['wpa'] = self.security_mode
125                if len(self.password) == hostapd_constants.MAX_WPA_PSK_LENGTH:
126                    settings['wpa_psk'] = self.password
127                else:
128                    settings['wpa_passphrase'] = self.password
129                if self.security_mode == hostapd_constants.MIXED:
130                    settings['wpa_pairwise'] = self.wpa_cipher
131                    settings['rsn_pairwise'] = self.wpa2_cipher
132                elif self.security_mode == hostapd_constants.WPA1:
133                    settings['wpa_pairwise'] = self.wpa_cipher
134                elif self.security_mode == hostapd_constants.WPA2:
135                    settings['rsn_pairwise'] = self.wpa2_cipher
136                if self.wpa3:
137                    settings['wpa_key_mgmt'] = 'SAE'
138                if self.wpa_group_rekey:
139                    settings['wpa_group_rekey'] = self.wpa_group_rekey
140                if self.wpa_strict_rekey:
141                    settings[
142                        'wpa_strict_rekey'] = hostapd_constants.WPA_STRICT_REKEY
143        return settings
144