blob: d97de7fe9b75a20a6315797e94a7d666e6a5d9d8 [file] [log] [blame]
snaramre5d4b8912019-12-13 23:39:35 +00001diff --git a/scapy/layers/ipsec.py b/scapy/layers/ipsec.py
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -05002index ae057ee1..24a1f6ea 100644
snaramre5d4b8912019-12-13 23:39:35 +00003--- a/scapy/layers/ipsec.py
4+++ b/scapy/layers/ipsec.py
Neale Rannsabc56602020-04-01 09:45:23 +00005@@ -138,6 +138,7 @@ bind_layers(IP, ESP, proto=socket.IPPROTO_ESP)
6 bind_layers(IPv6, ESP, nh=socket.IPPROTO_ESP)
7 bind_layers(UDP, ESP, dport=4500) # NAT-Traversal encapsulation
8 bind_layers(UDP, ESP, sport=4500) # NAT-Traversal encapsulation
9+bind_layers(UDP, ESP, dport=4545) # NAT-Traversal encapsulation - random port
10
11 ###############################################################################
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -050012
13@@ -359,11 +360,8 @@ class CryptAlgo(object):
snaramre5d4b8912019-12-13 23:39:35 +000014 encryptor = cipher.encryptor()
15
16 if self.is_aead:
17- if esn_en:
18- aad = struct.pack('!LLL', esp.spi, esn, esp.seq)
19- else:
20- aad = struct.pack('!LL', esp.spi, esp.seq)
21- encryptor.authenticate_additional_data(aad)
22+ encryptor.authenticate_additional_data(sa.build_aead(esp))
23+
24 data = encryptor.update(data) + encryptor.finalize()
25 data += encryptor.tag[:self.icv_size]
26 else:
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -050027@@ -400,12 +398,7 @@ class CryptAlgo(object):
snaramre5d4b8912019-12-13 23:39:35 +000028
29 if self.is_aead:
30 # Tag value check is done during the finalize method
31- if esn_en:
32- decryptor.authenticate_additional_data(
33- struct.pack('!LLL', esp.spi, esn, esp.seq))
34- else:
35- decryptor.authenticate_additional_data(
36- struct.pack('!LL', esp.spi, esp.seq))
37+ decryptor.authenticate_additional_data(sa.build_aead(esp))
38 try:
39 data = decryptor.update(data) + decryptor.finalize()
40 except InvalidTag as err:
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -050041@@ -445,6 +438,7 @@ if algorithms:
42 CRYPT_ALGOS['AES-CTR'] = CryptAlgo('AES-CTR',
43 cipher=algorithms.AES,
44 mode=modes.CTR,
45+ block_size=1,
46 iv_size=8,
47 salt_size=4,
48 format_mode_iv=_aes_ctr_format_mode_iv)
49@@ -452,6 +446,7 @@ if algorithms:
50 CRYPT_ALGOS['AES-GCM'] = CryptAlgo('AES-GCM',
51 cipher=algorithms.AES,
52 mode=modes.GCM,
53+ block_size=1,
54 salt_size=4,
55 iv_size=8,
56 icv_size=16,
57@@ -460,6 +455,7 @@ if algorithms:
58 CRYPT_ALGOS['AES-CCM'] = CryptAlgo('AES-CCM',
59 cipher=algorithms.AES,
60 mode=modes.CCM,
61+ block_size=1,
62 iv_size=8,
63 salt_size=3,
64 icv_size=16,
65@@ -544,7 +540,7 @@ class AuthAlgo(object):
snaramre5d4b8912019-12-13 23:39:35 +000066 else:
67 return self.mac(key, self.digestmod(), default_backend())
68
69- def sign(self, pkt, key):
70+ def sign(self, pkt, key, trailer=None):
71 """
72 Sign an IPsec (ESP or AH) packet with this algo.
73
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -050074@@ -560,16 +556,20 @@ class AuthAlgo(object):
snaramre5d4b8912019-12-13 23:39:35 +000075
76 if pkt.haslayer(ESP):
77 mac.update(raw(pkt[ESP]))
78+ if trailer:
79+ mac.update(trailer)
80 pkt[ESP].data += mac.finalize()[:self.icv_size]
81
82 elif pkt.haslayer(AH):
83 clone = zero_mutable_fields(pkt.copy(), sending=True)
84 mac.update(raw(clone))
85+ if trailer:
86+ mac.update(trailer)
87 pkt[AH].icv = mac.finalize()[:self.icv_size]
88
89 return pkt
90
91- def verify(self, pkt, key):
92+ def verify(self, pkt, key, trailer):
93 """
94 Check that the integrity check value (icv) of a packet is valid.
95
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -050096@@ -600,6 +600,8 @@ class AuthAlgo(object):
snaramre5d4b8912019-12-13 23:39:35 +000097 clone = zero_mutable_fields(pkt.copy(), sending=False)
98
99 mac.update(raw(clone))
100+ if trailer:
101+ mac.update(trailer) # bytearray(4)) #raw(trailer))
102 computed_icv = mac.finalize()[:self.icv_size]
103
104 # XXX: Cannot use mac.verify because the ICV can be truncated
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -0500105@@ -862,6 +864,23 @@ class SecurityAssociation(object):
snaramre5d4b8912019-12-13 23:39:35 +0000106 raise TypeError('nat_t_header must be %s' % UDP.name)
107 self.nat_t_header = nat_t_header
108
109+ def build_aead(self, esp):
110+ if self.esn_en:
111+ return (struct.pack('!LLL', esp.spi, self.seq_num >> 32, esp.seq))
112+ else:
113+ return (struct.pack('!LL', esp.spi, esp.seq))
114+
115+ def build_seq_num(self, num):
116+ # only lower order bits are transmitted
117+ # higher order bits are used in the ICV
118+ lower = num & 0xffffffff
119+ upper = num >> 32
120+
121+ if self.esn_en:
122+ return lower, struct.pack("!I", upper)
123+ else:
124+ return lower, None
125+
126 def check_spi(self, pkt):
127 if pkt.spi != self.spi:
128 raise TypeError('packet spi=0x%x does not match the SA spi=0x%x' %
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -0500129@@ -875,7 +894,8 @@ class SecurityAssociation(object):
snaramre5d4b8912019-12-13 23:39:35 +0000130 if len(iv) != self.crypt_algo.iv_size:
131 raise TypeError('iv length must be %s' % self.crypt_algo.iv_size) # noqa: E501
132
133- esp = _ESPPlain(spi=self.spi, seq=seq_num or self.seq_num, iv=iv)
134+ low_seq_num, high_seq_num = self.build_seq_num(seq_num or self.seq_num)
135+ esp = _ESPPlain(spi=self.spi, seq=low_seq_num, iv=iv)
136
137 if self.tunnel_header:
138 tunnel = self.tunnel_header.copy()
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -0500139@@ -899,7 +919,7 @@ class SecurityAssociation(object):
snaramre5d4b8912019-12-13 23:39:35 +0000140 esn_en=esn_en or self.esn_en,
141 esn=esn or self.esn)
142
143- self.auth_algo.sign(esp, self.auth_key)
144+ self.auth_algo.sign(esp, self.auth_key, high_seq_num)
145
146 if self.nat_t_header:
147 nat_t_header = self.nat_t_header.copy()
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -0500148@@ -926,7 +946,8 @@ class SecurityAssociation(object):
snaramre5d4b8912019-12-13 23:39:35 +0000149
150 def _encrypt_ah(self, pkt, seq_num=None):
151
152- ah = AH(spi=self.spi, seq=seq_num or self.seq_num,
153+ low_seq_num, high_seq_num = self.build_seq_num(seq_num or self.seq_num)
154+ ah = AH(spi=self.spi, seq=low_seq_num,
155 icv=b"\x00" * self.auth_algo.icv_size)
156
157 if self.tunnel_header:
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -0500158@@ -966,7 +987,8 @@ class SecurityAssociation(object):
snaramre5d4b8912019-12-13 23:39:35 +0000159 else:
160 ip_header.plen = len(ip_header.payload) + len(ah) + len(payload)
161
162- signed_pkt = self.auth_algo.sign(ip_header / ah / payload, self.auth_key) # noqa: E501
163+ signed_pkt = self.auth_algo.sign(ip_header / ah / payload,
164+ self.auth_key, high_seq_num) # noqa: E501
165
166 # sequence number must always change, unless specified by the user
167 if seq_num is None:
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -0500168@@ -1003,11 +1025,12 @@ class SecurityAssociation(object):
snaramre5d4b8912019-12-13 23:39:35 +0000169
170 def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None):
171
172+ low_seq_num, high_seq_num = self.build_seq_num(self.seq_num)
173 encrypted = pkt[ESP]
174
175 if verify:
176 self.check_spi(pkt)
177- self.auth_algo.verify(encrypted, self.auth_key)
178+ self.auth_algo.verify(encrypted, self.auth_key, high_seq_num)
179
180 esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key,
181 self.crypt_algo.icv_size or
Christian Hoppsfb7e7ed2019-11-03 07:02:15 -0500182@@ -1048,9 +1071,10 @@ class SecurityAssociation(object):
snaramre5d4b8912019-12-13 23:39:35 +0000183
184 def _decrypt_ah(self, pkt, verify=True):
185
186+ low_seq_num, high_seq_num = self.build_seq_num(self.seq_num)
187 if verify:
188 self.check_spi(pkt)
189- self.auth_algo.verify(pkt, self.auth_key)
190+ self.auth_algo.verify(pkt, self.auth_key, high_seq_num)
191
192 ah = pkt[AH]
193 payload = ah.payload