1#
2#   Copyright 2018 - The Android Open Source Project
3#
4#   Licensed under the Apache License, Version 2.0 (the "License");
5#   you may not use this file except in compliance with the License.
6#   You may obtain a copy of the License at
7#
8#       http://www.apache.org/licenses/LICENSE-2.0
9#
10#   Unless required by applicable law or agreed to in writing, software
11#   distributed under the License is distributed on an "AS IS" BASIS,
12#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13#   See the License for the specific language governing permissions and
14#   limitations under the License.
15
16import binascii
17import os
18import re
19
20from acts_contrib.test_utils.net import connectivity_const as cconst
21from acts import asserts
22
23PKTS = 5
24
25
26def make_key(len_bits):
27    asserts.assert_true(
28        len_bits % 8 == 0, "Unexpected key length. Should be a multiple "
29        "of 8, got %s" % len_bits)
30    return binascii.hexlify(os.urandom(int(len_bits / 8))).decode()
31
32
33def allocate_spis(ad, ip_a, ip_b, in_spi=None, out_spi=None):
34    """ Allocate in and out SPIs for android device
35
36    Args:
37      1. ad : android device object
38      2. ip_a : local IP address for In SPI
39      3. ip_b : remote IP address for Out SPI
40      4. in_spi : Generate In SPI with this value
41      5. out_spi : Generate Out SPI with this value
42
43    Returns:
44      List of In and Out SPI
45    """
46    in_spi_key = ad.droid.ipSecAllocateSecurityParameterIndex(ip_a, in_spi)
47    in_spi = ad.droid.ipSecGetSecurityParameterIndex(in_spi_key)
48    ad.log.info("In SPI: %s" % hex(in_spi))
49
50    out_spi_key = ad.droid.ipSecAllocateSecurityParameterIndex(ip_b, out_spi)
51    out_spi = ad.droid.ipSecGetSecurityParameterIndex(out_spi_key)
52    ad.log.info("Out SPI: %s" % hex(out_spi))
53
54    asserts.assert_true(in_spi and out_spi, "Failed to allocate SPIs")
55    return [in_spi_key, out_spi_key]
56
57
58def release_spis(ad, spis):
59    """ Destroy SPIs
60
61    Args:
62      1. ad : android device object
63      2. spis : list of SPI keys to destroy
64    """
65    for spi_key in spis:
66        ad.droid.ipSecReleaseSecurityParameterIndex(spi_key)
67        spi = ad.droid.ipSecGetSecurityParameterIndex(spi_key)
68        asserts.assert_true(not spi, "Failed to release SPI")
69
70
71def create_transport_mode_transforms(ad,
72                                     spis,
73                                     ip_a,
74                                     ip_b,
75                                     crypt_algo,
76                                     crypt_key,
77                                     auth_algo,
78                                     auth_key,
79                                     trunc_bit,
80                                     udp_encap_sock=None):
81    """ Create transport mode transforms on the device
82
83    Args:
84      1. ad : android device object
85      2. spis : spi keys of the SPIs created
86      3. ip_a : local IP addr
87      4. ip_b : remote IP addr
88      5. crypt_key : encryption key
89      6. auth_key : authentication key
90      7. udp_encap_sock : set udp encapsulation for ESP packets
91
92    Returns:
93      List of In and Out Transforms
94    """
95    in_transform = ad.droid.ipSecCreateTransportModeTransform(
96        crypt_algo, crypt_key, auth_algo, auth_key, trunc_bit, spis[0], ip_b,
97        udp_encap_sock)
98    ad.log.info("In Transform: %s" % in_transform)
99    out_transform = ad.droid.ipSecCreateTransportModeTransform(
100        crypt_algo, crypt_key, auth_algo, auth_key, trunc_bit, spis[1], ip_a,
101        udp_encap_sock)
102    ad.log.info("Out Transform: %s" % out_transform)
103    asserts.assert_true(in_transform and out_transform,
104                        "Failed to create transforms")
105    return [in_transform, out_transform]
106
107
108def destroy_transport_mode_transforms(ad, transforms):
109    """ Destroy transforms on the device
110
111    Args:
112      1. ad : android device object
113      2. transforms : list to transform keys to destroy
114    """
115    for transform in transforms:
116        ad.droid.ipSecDestroyTransportModeTransform(transform)
117        status = ad.droid.ipSecGetTransformStatus(transform)
118        ad.log.info("Transform status: %s" % status)
119        asserts.assert_true(not status, "Failed to destroy transform")
120
121
122def apply_transport_mode_transforms_file_descriptors(ad, fd, transforms):
123    """ Apply transpot mode transform to FileDescriptor object
124
125    Args:
126      1. ad - android device object
127      2. fd - FileDescriptor key
128      3. transforms - list of in and out transforms
129    """
130    in_transform = ad.droid.ipSecApplyTransportModeTransformFileDescriptor(
131        fd, cconst.DIRECTION_IN, transforms[0])
132    out_transform = ad.droid.ipSecApplyTransportModeTransformFileDescriptor(
133        fd, cconst.DIRECTION_OUT, transforms[1])
134    asserts.assert_true(in_transform and out_transform,
135                        "Failed to apply transform")
136    ip_xfrm_state = ad.adb.shell("ip -s xfrm state")
137    ad.log.info("XFRM STATE:\n%s\n" % ip_xfrm_state)
138    ip_xfrm_policy = ad.adb.shell("ip -s xfrm policy")
139    ad.log.info("XFRM POLICY:\n%s\n" % ip_xfrm_policy)
140
141
142def remove_transport_mode_transforms_file_descriptors(ad, fd):
143    """ Remove transport mode transform from FileDescriptor object
144
145    Args:
146      1. ad - android device object
147      2. socket - FileDescriptor key
148    """
149    status = ad.droid.ipSecRemoveTransportModeTransformsFileDescriptor(fd)
150    asserts.assert_true(status, "Failed to remove transform")
151
152
153def apply_transport_mode_transforms_datagram_socket(ad, socket, transforms):
154    """ Apply transport mode transform to DatagramSocket object
155
156    Args:
157      1. ad - android device object
158      2. socket - DatagramSocket object key
159      3. transforms - list of in and out transforms
160    """
161    in_tfrm_status = ad.droid.ipSecApplyTransportModeTransformDatagramSocket(
162        socket, cconst.DIRECTION_IN, transforms[0])
163    out_tfrm_status = ad.droid.ipSecApplyTransportModeTransformDatagramSocket(
164        socket, cconst.DIRECTION_OUT, transforms[1])
165    asserts.assert_true(in_tfrm_status and out_tfrm_status,
166                        "Failed to apply transform")
167
168    ip_xfrm_state = ad.adb.shell("ip -s xfrm state")
169    ad.log.info("XFRM STATE:\n%s\n" % ip_xfrm_state)
170
171
172def remove_transport_mode_transforms_datagram_socket(ad, socket):
173    """ Remove transport mode transform from DatagramSocket object
174
175    Args:
176      1. ad - android device object
177      2. socket - DatagramSocket object key
178    """
179    status = ad.droid.ipSecRemoveTransportModeTransformsDatagramSocket(socket)
180    asserts.assert_true(status, "Failed to remove transform")
181
182
183def apply_transport_mode_transforms_socket(ad, socket, transforms):
184    """ Apply transport mode transform to Socket object
185
186    Args:
187      1. ad - android device object
188      2. socket - Socket object key
189      3. transforms - list of in and out transforms
190    """
191    in_tfrm_status = ad.droid.ipSecApplyTransportModeTransformSocket(
192        socket, cconst.DIRECTION_IN, transforms[0])
193    out_tfrm_status = ad.droid.ipSecApplyTransportModeTransformSocket(
194        socket, cconst.DIRECTION_OUT, transforms[1])
195    asserts.assert_true(in_tfrm_status and out_tfrm_status,
196                        "Failed to apply transform")
197
198    ip_xfrm_state = ad.adb.shell("ip -s xfrm state")
199    ad.log.info("XFRM STATE:\n%s\n" % ip_xfrm_state)
200
201
202def remove_transport_mode_transforms_socket(ad, socket):
203    """ Remove transport mode transform from Socket object
204
205    Args:
206      1. ad - android device object
207      2. socket - Socket object key
208    """
209    status = ad.droid.ipSecRemoveTransportModeTransformsSocket(socket)
210    asserts.assert_true(status, "Failed to remove transform")
211
212
213def verify_esp_packets(ads):
214    """ Verify that encrypted ESP packets are sent
215
216    Args:
217      1. ads - Verify ESP packets on all devices
218    """
219    for ad in ads:
220        ip_xfrm_state = ad.adb.shell("ip -s xfrm state")
221        ad.log.info("XFRM STATE on %s:\n%s\n" % (ad.serial, ip_xfrm_state))
222        pattern = re.findall(r'\d+\(packets\)', ip_xfrm_state)
223        esp_pkts = False
224        for _ in pattern:
225            if int(_.split('(')[0]) >= PKTS:
226                esp_pkts = True
227                break
228        asserts.assert_true(esp_pkts, "Could not find ESP pkts")
229
230
231def generate_random_crypt_auth_combo():
232    """ Generate every possible combination of crypt and auth keys,
233        auth algo, trunc bits supported by IpSecManager
234    """
235    crypt_key_length = [128, 192, 256]
236    auth_method_key = {
237        cconst.AUTH_HMAC_MD5: 128,
238        cconst.AUTH_HMAC_SHA1: 160,
239        cconst.AUTH_HMAC_SHA256: 256,
240        cconst.AUTH_HMAC_SHA384: 384,
241        cconst.AUTH_HMAC_SHA512: 512
242    }
243    auth_method_trunc = {
244        cconst.AUTH_HMAC_MD5: list(range(96, 136, 8)),
245        cconst.AUTH_HMAC_SHA1: list(range(96, 168, 8)),
246        cconst.AUTH_HMAC_SHA256: list(range(96, 264, 8)),
247        cconst.AUTH_HMAC_SHA384: list(range(192, 392, 8)),
248        cconst.AUTH_HMAC_SHA512: list(range(256, 520, 8))
249    }
250    return_list = []
251    for c in crypt_key_length:
252        for k in auth_method_key.keys():
253            auth_key = auth_method_key[k]
254            lst = auth_method_trunc[k]
255            for t in lst:
256                combo = []
257                combo.append(c)
258                combo.append(k)
259                combo.append(auth_key)
260                combo.append(t)
261                return_list.append(combo)
262
263    return return_list
264