1#!/usr/bin/python 2# 3# Copyright 2017 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# pylint: disable=g-bad-todo,g-bad-file-header,wildcard-import 18from errno import * # pylint: disable=wildcard-import 19import os 20import itertools 21from scapy import all as scapy 22from socket import * # pylint: disable=wildcard-import 23import subprocess 24import threading 25import unittest 26 27import multinetwork_base 28import net_test 29from tun_twister import TapTwister 30import util 31import xfrm 32import xfrm_base 33import xfrm_test 34 35ANY_KVER = net_test.LINUX_ANY_VERSION 36 37# List of encryption algorithms for use in ParamTests. 38CRYPT_ALGOS = [ 39 (xfrm.XfrmAlgo((xfrm.XFRM_EALG_CBC_AES, 128)), ANY_KVER), 40 (xfrm.XfrmAlgo((xfrm.XFRM_EALG_CBC_AES, 192)), ANY_KVER), 41 (xfrm.XfrmAlgo((xfrm.XFRM_EALG_CBC_AES, 256)), ANY_KVER), 42 # RFC 3686 specifies that key length must be 128, 192 or 256 bits, with 43 # an additional 4 bytes (32 bits) of nonce. A fresh nonce value MUST be 44 # assigned for each SA. 45 # CTR-AES is enforced since kernel version 5.8 46 (xfrm.XfrmAlgo((xfrm.XFRM_EALG_CTR_AES, 128+32)), (5, 8)), 47 (xfrm.XfrmAlgo((xfrm.XFRM_EALG_CTR_AES, 192+32)), (5, 8)), 48 (xfrm.XfrmAlgo((xfrm.XFRM_EALG_CTR_AES, 256+32)), (5, 8)), 49] 50 51# List of auth algorithms for use in ParamTests. 52AUTH_ALGOS = [ 53 # RFC 4868 specifies that the only supported truncation length is half the 54 # hash size. 55 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_MD5, 128, 96)), ANY_KVER), 56 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA1, 160, 96)), ANY_KVER), 57 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA256, 256, 128)), ANY_KVER), 58 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA384, 384, 192)), ANY_KVER), 59 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA512, 512, 256)), ANY_KVER), 60 # Test larger truncation lengths for good measure. 61 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_MD5, 128, 128)), ANY_KVER), 62 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA1, 160, 160)), ANY_KVER), 63 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA256, 256, 256)), ANY_KVER), 64 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA384, 384, 384)), ANY_KVER), 65 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_HMAC_SHA512, 512, 512)), ANY_KVER), 66 # RFC 3566 specifies that the only supported truncation length 67 # is 96 bits. 68 # XCBC-AES is enforced since kernel version 5.8 69 (xfrm.XfrmAlgoAuth((xfrm.XFRM_AALG_AUTH_XCBC_AES, 128, 96)), (5, 8)), 70] 71 72# List of aead algorithms for use in ParamTests. 73AEAD_ALGOS = [ 74 # RFC 4106 specifies that key length must be 128, 192 or 256 bits, 75 # with an additional 4 bytes (32 bits) of salt. The salt must be unique 76 # for each new SA using the same key. 77 # RFC 4106 specifies that ICV length must be 8, 12, or 16 bytes 78 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 128+32, 8*8)), ANY_KVER), 79 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 128+32, 12*8)), ANY_KVER), 80 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 128+32, 16*8)), ANY_KVER), 81 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 192+32, 8*8)), ANY_KVER), 82 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 192+32, 12*8)), ANY_KVER), 83 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 192+32, 16*8)), ANY_KVER), 84 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 256+32, 8*8)), ANY_KVER), 85 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 256+32, 12*8)), ANY_KVER), 86 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_GCM_AES, 256+32, 16*8)), ANY_KVER), 87 # RFC 7634 specifies that key length must be 256 bits, with an additional 88 # 4 bytes (32 bits) of nonce. A fresh nonce value MUST be assigned for 89 # each SA. RFC 7634 also specifies that ICV length must be 16 bytes. 90 # ChaCha20-Poly1305 is enforced since kernel version 5.8 91 (xfrm.XfrmAlgoAead((xfrm.XFRM_AEAD_CHACHA20_POLY1305, 256+32, 16*8)), (5, 8)), 92] 93 94def GenerateKey(key_len): 95 if key_len % 8 != 0: 96 raise ValueError("Invalid key length in bits: " + str(key_len)) 97 return os.urandom(key_len / 8) 98 99# Does the kernel support this algorithm? 100def HaveAlgo(crypt_algo, auth_algo, aead_algo): 101 try: 102 test_xfrm = xfrm.Xfrm() 103 test_xfrm.FlushSaInfo() 104 test_xfrm.FlushPolicyInfo() 105 106 test_xfrm.AddSaInfo( 107 src=xfrm_test.TEST_ADDR1, 108 dst=xfrm_test.TEST_ADDR2, 109 spi=xfrm_test.TEST_SPI, 110 mode=xfrm.XFRM_MODE_TRANSPORT, 111 reqid=100, 112 encryption=(crypt_algo, 113 GenerateKey(crypt_algo.key_len)) if crypt_algo else None, 114 auth_trunc=(auth_algo, 115 GenerateKey(auth_algo.key_len)) if auth_algo else None, 116 aead=(aead_algo, GenerateKey(aead_algo.key_len)) if aead_algo else None, 117 encap=None, 118 mark=None, 119 output_mark=None) 120 121 test_xfrm.FlushSaInfo() 122 test_xfrm.FlushPolicyInfo() 123 124 return True 125 except IOError as err: 126 if err.errno == ENOSYS: 127 return False 128 else: 129 print("Unexpected error:", err.errno) 130 return True 131 132# Dictionary to record the algorithm state. Mark the state True if this 133# algorithm is enforced or enabled on this kernel. Otherwise, mark it 134# False. 135algoState = {} 136 137def AlgoEnforcedOrEnabled(crypt, auth, aead, target_algo, target_kernel): 138 if algoState.get(target_algo) is None: 139 algoState[target_algo] = net_test.LINUX_VERSION >= target_kernel or HaveAlgo( 140 crypt, auth, aead) 141 return algoState.get(target_algo) 142 143# Return true if this algorithm should be enforced or is enabled on this kernel 144def AuthEnforcedOrEnabled(authCase): 145 auth = authCase[0] 146 crypt = xfrm.XfrmAlgo(("ecb(cipher_null)", 0)) 147 return AlgoEnforcedOrEnabled(crypt, auth, None, auth.name, authCase[1]) 148 149# Return true if this algorithm should be enforced or is enabled on this kernel 150def CryptEnforcedOrEnabled(cryptCase): 151 crypt = cryptCase[0] 152 auth = xfrm.XfrmAlgoAuth(("digest_null", 0, 0)) 153 return AlgoEnforcedOrEnabled(crypt, auth, None, crypt.name, cryptCase[1]) 154 155# Return true if this algorithm should be enforced or is enabled on this kernel 156def AeadEnforcedOrEnabled(aeadCase): 157 aead = aeadCase[0] 158 return AlgoEnforcedOrEnabled(None, None, aead, aead.name, aeadCase[1]) 159 160def InjectTests(): 161 XfrmAlgorithmTest.InjectTests() 162 163 164class XfrmAlgorithmTest(xfrm_base.XfrmLazyTest): 165 @classmethod 166 def InjectTests(cls): 167 VERSIONS = (4, 6) 168 TYPES = (SOCK_DGRAM, SOCK_STREAM) 169 170 # Tests all combinations of auth & crypt. Mutually exclusive with aead. 171 param_list = itertools.product(VERSIONS, TYPES, AUTH_ALGOS, CRYPT_ALGOS, 172 [None]) 173 util.InjectParameterizedTest(cls, param_list, cls.TestNameGenerator) 174 175 # Tests all combinations of aead. Mutually exclusive with auth/crypt. 176 param_list = itertools.product(VERSIONS, TYPES, [None], [None], AEAD_ALGOS) 177 util.InjectParameterizedTest(cls, param_list, cls.TestNameGenerator) 178 179 @staticmethod 180 def TestNameGenerator(version, proto, authCase, cryptCase, aeadCase): 181 # Produce a unique and readable name for each test. e.g. 182 # testSocketPolicySimple_cbc-aes_256_hmac-sha512_512_256_IPv6_UDP 183 param_string = "" 184 if cryptCase is not None: 185 crypt = cryptCase[0] 186 param_string += "%s_%d_" % (crypt.name, crypt.key_len) 187 188 if authCase is not None: 189 auth = authCase[0] 190 param_string += "%s_%d_%d_" % (auth.name, auth.key_len, 191 auth.trunc_len) 192 193 if aeadCase is not None: 194 aead = aeadCase[0] 195 param_string += "%s_%d_%d_" % (aead.name, aead.key_len, 196 aead.icv_len) 197 198 param_string += "%s_%s" % ("IPv4" if version == 4 else "IPv6", 199 "UDP" if proto == SOCK_DGRAM else "TCP") 200 return param_string 201 202 def ParamTestSocketPolicySimple(self, version, proto, authCase, cryptCase, aeadCase): 203 """Test two-way traffic using transport mode and socket policies.""" 204 205 # Bypass the test if any algorithm going to be tested is not enforced 206 # or enabled on this kernel 207 if authCase is not None and not AuthEnforcedOrEnabled(authCase): 208 return 209 if cryptCase is not None and not CryptEnforcedOrEnabled(cryptCase): 210 return 211 if aeadCase is not None and not AeadEnforcedOrEnabled(aeadCase): 212 return 213 214 auth = authCase[0] if authCase else None 215 crypt = cryptCase[0] if cryptCase else None 216 aead = aeadCase[0] if aeadCase else None 217 218 def AssertEncrypted(packet): 219 # This gives a free pass to ICMP and ICMPv6 packets, which show up 220 # nondeterministically in tests. 221 self.assertEqual(None, 222 packet.getlayer(scapy.UDP), 223 "UDP packet sent in the clear") 224 self.assertEqual(None, 225 packet.getlayer(scapy.TCP), 226 "TCP packet sent in the clear") 227 228 # We create a pair of sockets, "left" and "right", that will talk to each 229 # other using transport mode ESP. Because of TapTwister, both sockets 230 # perceive each other as owning "remote_addr". 231 netid = self.RandomNetid() 232 family = net_test.GetAddressFamily(version) 233 local_addr = self.MyAddress(version, netid) 234 remote_addr = self.GetRemoteSocketAddress(version) 235 auth_left = (xfrm.XfrmAlgoAuth((auth.name, auth.key_len, auth.trunc_len)), 236 os.urandom(auth.key_len / 8)) if auth else None 237 auth_right = (xfrm.XfrmAlgoAuth((auth.name, auth.key_len, auth.trunc_len)), 238 os.urandom(auth.key_len / 8)) if auth else None 239 crypt_left = (xfrm.XfrmAlgo((crypt.name, crypt.key_len)), 240 os.urandom(crypt.key_len / 8)) if crypt else None 241 crypt_right = (xfrm.XfrmAlgo((crypt.name, crypt.key_len)), 242 os.urandom(crypt.key_len / 8)) if crypt else None 243 aead_left = (xfrm.XfrmAlgoAead((aead.name, aead.key_len, aead.icv_len)), 244 os.urandom(aead.key_len / 8)) if aead else None 245 aead_right = (xfrm.XfrmAlgoAead((aead.name, aead.key_len, aead.icv_len)), 246 os.urandom(aead.key_len / 8)) if aead else None 247 spi_left = 0xbeefface 248 spi_right = 0xcafed00d 249 req_ids = [100, 200, 300, 400] # Used to match templates and SAs. 250 251 # Left outbound SA 252 self.xfrm.AddSaInfo( 253 src=local_addr, 254 dst=remote_addr, 255 spi=spi_right, 256 mode=xfrm.XFRM_MODE_TRANSPORT, 257 reqid=req_ids[0], 258 encryption=crypt_right, 259 auth_trunc=auth_right, 260 aead=aead_right, 261 encap=None, 262 mark=None, 263 output_mark=None) 264 # Right inbound SA 265 self.xfrm.AddSaInfo( 266 src=remote_addr, 267 dst=local_addr, 268 spi=spi_right, 269 mode=xfrm.XFRM_MODE_TRANSPORT, 270 reqid=req_ids[1], 271 encryption=crypt_right, 272 auth_trunc=auth_right, 273 aead=aead_right, 274 encap=None, 275 mark=None, 276 output_mark=None) 277 # Right outbound SA 278 self.xfrm.AddSaInfo( 279 src=local_addr, 280 dst=remote_addr, 281 spi=spi_left, 282 mode=xfrm.XFRM_MODE_TRANSPORT, 283 reqid=req_ids[2], 284 encryption=crypt_left, 285 auth_trunc=auth_left, 286 aead=aead_left, 287 encap=None, 288 mark=None, 289 output_mark=None) 290 # Left inbound SA 291 self.xfrm.AddSaInfo( 292 src=remote_addr, 293 dst=local_addr, 294 spi=spi_left, 295 mode=xfrm.XFRM_MODE_TRANSPORT, 296 reqid=req_ids[3], 297 encryption=crypt_left, 298 auth_trunc=auth_left, 299 aead=aead_left, 300 encap=None, 301 mark=None, 302 output_mark=None) 303 304 # Make two sockets. 305 sock_left = socket(family, proto, 0) 306 sock_left.settimeout(2.0) 307 sock_left.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 308 self.SelectInterface(sock_left, netid, "mark") 309 sock_right = socket(family, proto, 0) 310 sock_right.settimeout(2.0) 311 sock_right.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 312 self.SelectInterface(sock_right, netid, "mark") 313 314 # For UDP, set SO_LINGER to 0, to prevent TCP sockets from hanging around 315 # in a TIME_WAIT state. 316 if proto == SOCK_STREAM: 317 net_test.DisableFinWait(sock_left) 318 net_test.DisableFinWait(sock_right) 319 320 # Apply the left outbound socket policy. 321 xfrm_base.ApplySocketPolicy(sock_left, family, xfrm.XFRM_POLICY_OUT, 322 spi_right, req_ids[0], None) 323 # Apply right inbound socket policy. 324 xfrm_base.ApplySocketPolicy(sock_right, family, xfrm.XFRM_POLICY_IN, 325 spi_right, req_ids[1], None) 326 # Apply right outbound socket policy. 327 xfrm_base.ApplySocketPolicy(sock_right, family, xfrm.XFRM_POLICY_OUT, 328 spi_left, req_ids[2], None) 329 # Apply left inbound socket policy. 330 xfrm_base.ApplySocketPolicy(sock_left, family, xfrm.XFRM_POLICY_IN, 331 spi_left, req_ids[3], None) 332 333 server_ready = threading.Event() 334 server_error = None # Save exceptions thrown by the server. 335 336 def TcpServer(sock, client_port): 337 try: 338 sock.listen(1) 339 server_ready.set() 340 accepted, peer = sock.accept() 341 self.assertEqual(remote_addr, peer[0]) 342 self.assertEqual(client_port, peer[1]) 343 data = accepted.recv(2048) 344 self.assertEqual("hello request", data) 345 accepted.send("hello response") 346 except Exception as e: 347 server_error = e 348 finally: 349 sock.close() 350 351 def UdpServer(sock, client_port): 352 try: 353 server_ready.set() 354 data, peer = sock.recvfrom(2048) 355 self.assertEqual(remote_addr, peer[0]) 356 self.assertEqual(client_port, peer[1]) 357 self.assertEqual("hello request", data) 358 sock.sendto("hello response", peer) 359 except Exception as e: 360 server_error = e 361 finally: 362 sock.close() 363 364 # Server and client need to know each other's port numbers in advance. 365 wildcard_addr = net_test.GetWildcardAddress(version) 366 sock_left.bind((wildcard_addr, 0)) 367 sock_right.bind((wildcard_addr, 0)) 368 left_port = sock_left.getsockname()[1] 369 right_port = sock_right.getsockname()[1] 370 371 # Start the appropriate server type on sock_right. 372 target = TcpServer if proto == SOCK_STREAM else UdpServer 373 server = threading.Thread( 374 target=target, 375 args=(sock_right, left_port), 376 name="SocketServer") 377 server.start() 378 # Wait for server to be ready before attempting to connect. TCP retries 379 # hide this problem, but UDP will fail outright if the server socket has 380 # not bound when we send. 381 self.assertTrue(server_ready.wait(2.0), "Timed out waiting for server thread") 382 383 with TapTwister(fd=self.tuns[netid].fileno(), validator=AssertEncrypted): 384 sock_left.connect((remote_addr, right_port)) 385 sock_left.send("hello request") 386 data = sock_left.recv(2048) 387 self.assertEqual("hello response", data) 388 sock_left.close() 389 server.join() 390 if server_error: 391 raise server_error 392 393 394if __name__ == "__main__": 395 XfrmAlgorithmTest.InjectTests() 396 unittest.main() 397