ipsec: Support MPLS over IPSec[46] interface
[vpp.git] / test / patches / scapy-2.4.3 / ipsec.patch
1 diff --git a/scapy/layers/ipsec.py b/scapy/layers/ipsec.py
2 index ae057ee1..d7a21e8b 100644
3 --- a/scapy/layers/ipsec.py
4 +++ b/scapy/layers/ipsec.py
5 @@ -56,6 +56,7 @@ from scapy.fields import ByteEnumField, ByteField, IntField, PacketField, \
6      ShortField, StrField, XIntField, XStrField, XStrLenField
7  from scapy.packet import Packet, bind_layers, Raw
8  from scapy.layers.inet import IP, UDP
9 +from scapy.contrib.mpls import MPLS
10  import scapy.modules.six as six
11  from scapy.modules.six.moves import range
12  from scapy.layers.inet6 import IPv6, IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, \
13 @@ -138,6 +139,7 @@ bind_layers(IP, ESP, proto=socket.IPPROTO_ESP)
14  bind_layers(IPv6, ESP, nh=socket.IPPROTO_ESP)
15  bind_layers(UDP, ESP, dport=4500)  # NAT-Traversal encapsulation
16  bind_layers(UDP, ESP, sport=4500)  # NAT-Traversal encapsulation
17 +bind_layers(UDP, ESP, dport=4545)  # NAT-Traversal encapsulation - random port
18  
19  ###############################################################################
20  
21 @@ -359,11 +361,8 @@ class CryptAlgo(object):
22              encryptor = cipher.encryptor()
23  
24              if self.is_aead:
25 -                if esn_en:
26 -                    aad = struct.pack('!LLL', esp.spi, esn, esp.seq)
27 -                else:
28 -                    aad = struct.pack('!LL', esp.spi, esp.seq)
29 -                encryptor.authenticate_additional_data(aad)
30 +                encryptor.authenticate_additional_data(sa.build_aead(esp))
31 +
32                  data = encryptor.update(data) + encryptor.finalize()
33                  data += encryptor.tag[:self.icv_size]
34              else:
35 @@ -400,12 +399,7 @@ class CryptAlgo(object):
36  
37              if self.is_aead:
38                  # Tag value check is done during the finalize method
39 -                if esn_en:
40 -                    decryptor.authenticate_additional_data(
41 -                        struct.pack('!LLL', esp.spi, esn, esp.seq))
42 -                else:
43 -                    decryptor.authenticate_additional_data(
44 -                        struct.pack('!LL', esp.spi, esp.seq))
45 +                decryptor.authenticate_additional_data(sa.build_aead(esp))
46              try:
47                  data = decryptor.update(data) + decryptor.finalize()
48              except InvalidTag as err:
49 @@ -445,6 +439,7 @@ if algorithms:
50      CRYPT_ALGOS['AES-CTR'] = CryptAlgo('AES-CTR',
51                                         cipher=algorithms.AES,
52                                         mode=modes.CTR,
53 +                                       block_size=1,
54                                         iv_size=8,
55                                         salt_size=4,
56                                         format_mode_iv=_aes_ctr_format_mode_iv)
57 @@ -452,6 +447,7 @@ if algorithms:
58      CRYPT_ALGOS['AES-GCM'] = CryptAlgo('AES-GCM',
59                                         cipher=algorithms.AES,
60                                         mode=modes.GCM,
61 +                                       block_size=1,
62                                         salt_size=4,
63                                         iv_size=8,
64                                         icv_size=16,
65 @@ -460,6 +456,7 @@ if algorithms:
66          CRYPT_ALGOS['AES-CCM'] = CryptAlgo('AES-CCM',
67                                             cipher=algorithms.AES,
68                                             mode=modes.CCM,
69 +                                           block_size=1,
70                                             iv_size=8,
71                                             salt_size=3,
72                                             icv_size=16,
73 @@ -544,7 +541,7 @@ class AuthAlgo(object):
74          else:
75              return self.mac(key, self.digestmod(), default_backend())
76  
77 -    def sign(self, pkt, key):
78 +    def sign(self, pkt, key, trailer=None):
79          """
80          Sign an IPsec (ESP or AH) packet with this algo.
81  
82 @@ -560,16 +557,20 @@ class AuthAlgo(object):
83  
84          if pkt.haslayer(ESP):
85              mac.update(raw(pkt[ESP]))
86 +            if trailer:
87 +                mac.update(trailer)
88              pkt[ESP].data += mac.finalize()[:self.icv_size]
89  
90          elif pkt.haslayer(AH):
91              clone = zero_mutable_fields(pkt.copy(), sending=True)
92              mac.update(raw(clone))
93 +            if trailer:
94 +                mac.update(trailer)
95              pkt[AH].icv = mac.finalize()[:self.icv_size]
96  
97          return pkt
98  
99 -    def verify(self, pkt, key):
100 +    def verify(self, pkt, key, trailer):
101          """
102          Check that the integrity check value (icv) of a packet is valid.
103  
104 @@ -600,6 +601,8 @@ class AuthAlgo(object):
105              clone = zero_mutable_fields(pkt.copy(), sending=False)
106  
107          mac.update(raw(clone))
108 +        if trailer:
109 +            mac.update(trailer) # bytearray(4)) #raw(trailer))
110          computed_icv = mac.finalize()[:self.icv_size]
111  
112          # XXX: Cannot use mac.verify because the ICV can be truncated
113 @@ -788,7 +791,7 @@ class SecurityAssociation(object):
114      This class is responsible of "encryption" and "decryption" of IPsec packets.  # noqa: E501
115      """
116  
117 -    SUPPORTED_PROTOS = (IP, IPv6)
118 +    SUPPORTED_PROTOS = (IP, IPv6, MPLS)
119  
120      def __init__(self, proto, spi, seq_num=1, crypt_algo=None, crypt_key=None,
121                   auth_algo=None, auth_key=None, tunnel_header=None, nat_t_header=None, esn_en=False, esn=0):   # noqa: E501
122 @@ -862,6 +865,23 @@ class SecurityAssociation(object):
123                  raise TypeError('nat_t_header must be %s' % UDP.name)
124          self.nat_t_header = nat_t_header
125  
126 +    def build_aead(self, esp):
127 +        if self.esn_en:
128 +            return (struct.pack('!LLL', esp.spi, self.seq_num >> 32, esp.seq))
129 +        else:
130 +            return (struct.pack('!LL', esp.spi, esp.seq))
131 +
132 +    def build_seq_num(self, num):
133 +        # only lower order bits are  transmitted
134 +        # higher order bits are used in the ICV
135 +        lower = num & 0xffffffff
136 +        upper = num >> 32
137 +
138 +        if self.esn_en:
139 +            return lower, struct.pack("!I", upper)
140 +        else:
141 +            return lower, None
142 +
143      def check_spi(self, pkt):
144          if pkt.spi != self.spi:
145              raise TypeError('packet spi=0x%x does not match the SA spi=0x%x' %
146 @@ -875,7 +895,8 @@ class SecurityAssociation(object):
147              if len(iv) != self.crypt_algo.iv_size:
148                  raise TypeError('iv length must be %s' % self.crypt_algo.iv_size)  # noqa: E501
149  
150 -        esp = _ESPPlain(spi=self.spi, seq=seq_num or self.seq_num, iv=iv)
151 +        low_seq_num, high_seq_num = self.build_seq_num(seq_num or self.seq_num)
152 +        esp = _ESPPlain(spi=self.spi, seq=low_seq_num, iv=iv)
153  
154          if self.tunnel_header:
155              tunnel = self.tunnel_header.copy()
156 @@ -899,7 +920,7 @@ class SecurityAssociation(object):
157                                        esn_en=esn_en or self.esn_en,
158                                        esn=esn or self.esn)
159  
160 -        self.auth_algo.sign(esp, self.auth_key)
161 +        self.auth_algo.sign(esp, self.auth_key, high_seq_num)
162  
163          if self.nat_t_header:
164              nat_t_header = self.nat_t_header.copy()
165 @@ -926,7 +947,8 @@ class SecurityAssociation(object):
166  
167      def _encrypt_ah(self, pkt, seq_num=None):
168  
169 -        ah = AH(spi=self.spi, seq=seq_num or self.seq_num,
170 +        low_seq_num, high_seq_num = self.build_seq_num(seq_num or self.seq_num)
171 +        ah = AH(spi=self.spi, seq=low_seq_num,
172                  icv=b"\x00" * self.auth_algo.icv_size)
173  
174          if self.tunnel_header:
175 @@ -966,7 +988,8 @@ class SecurityAssociation(object):
176          else:
177              ip_header.plen = len(ip_header.payload) + len(ah) + len(payload)
178  
179 -        signed_pkt = self.auth_algo.sign(ip_header / ah / payload, self.auth_key)  # noqa: E501
180 +        signed_pkt = self.auth_algo.sign(ip_header / ah / payload,
181 +                                         self.auth_key, high_seq_num)  # noqa: E501
182  
183          # sequence number must always change, unless specified by the user
184          if seq_num is None:
185 @@ -1003,11 +1026,12 @@ class SecurityAssociation(object):
186  
187      def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None):
188  
189 +        low_seq_num, high_seq_num = self.build_seq_num(self.seq_num)
190          encrypted = pkt[ESP]
191  
192          if verify:
193              self.check_spi(pkt)
194 -            self.auth_algo.verify(encrypted, self.auth_key)
195 +            self.auth_algo.verify(encrypted, self.auth_key, high_seq_num)
196  
197          esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key,
198                                        self.crypt_algo.icv_size or
199 @@ -1048,9 +1072,10 @@ class SecurityAssociation(object):
200  
201      def _decrypt_ah(self, pkt, verify=True):
202  
203 +        low_seq_num, high_seq_num = self.build_seq_num(self.seq_num)
204          if verify:
205              self.check_spi(pkt)
206 -            self.auth_algo.verify(pkt, self.auth_key)
207 +            self.auth_algo.verify(pkt, self.auth_key, high_seq_num)
208  
209          ah = pkt[AH]
210          payload = ah.payload