IPSEC-GRE: fixes and API update to common types.
[vpp.git] / src / vnet / ipsec / ipsec_sa.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
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  */
15 #ifndef __IPSEC_SPD_SA_H__
16 #define __IPSEC_SPD_SA_H__
17
18 #include <vlib/vlib.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/fib/fib_node.h>
21
22 #define IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE (64)
23
24 #define foreach_ipsec_crypto_alg    \
25   _ (0, NONE, "none")               \
26   _ (1, AES_CBC_128, "aes-cbc-128") \
27   _ (2, AES_CBC_192, "aes-cbc-192") \
28   _ (3, AES_CBC_256, "aes-cbc-256") \
29   _ (4, AES_CTR_128, "aes-ctr-128") \
30   _ (5, AES_CTR_192, "aes-ctr-192") \
31   _ (6, AES_CTR_256, "aes-ctr-256") \
32   _ (7, AES_GCM_128, "aes-gcm-128") \
33   _ (8, AES_GCM_192, "aes-gcm-192") \
34   _ (9, AES_GCM_256, "aes-gcm-256") \
35   _ (10, DES_CBC, "des-cbc")        \
36   _ (11, 3DES_CBC, "3des-cbc")
37
38 typedef enum
39 {
40 #define _(v, f, s) IPSEC_CRYPTO_ALG_##f = v,
41   foreach_ipsec_crypto_alg
42 #undef _
43     IPSEC_CRYPTO_N_ALG,
44 } ipsec_crypto_alg_t;
45
46 #define foreach_ipsec_integ_alg                                            \
47   _ (0, NONE, "none")                                                      \
48   _ (1, MD5_96, "md5-96")           /* RFC2403 */                          \
49   _ (2, SHA1_96, "sha1-96")         /* RFC2404 */                          \
50   _ (3, SHA_256_96, "sha-256-96")   /* draft-ietf-ipsec-ciph-sha-256-00 */ \
51   _ (4, SHA_256_128, "sha-256-128") /* RFC4868 */                          \
52   _ (5, SHA_384_192, "sha-384-192") /* RFC4868 */                          \
53   _ (6, SHA_512_256, "sha-512-256")     /* RFC4868 */
54
55 typedef enum
56 {
57 #define _(v, f, s) IPSEC_INTEG_ALG_##f = v,
58   foreach_ipsec_integ_alg
59 #undef _
60     IPSEC_INTEG_N_ALG,
61 } ipsec_integ_alg_t;
62
63 typedef enum
64 {
65   IPSEC_PROTOCOL_AH = 0,
66   IPSEC_PROTOCOL_ESP = 1
67 } ipsec_protocol_t;
68
69 #define IPSEC_N_PROTOCOLS (IPSEC_PROTOCOL_ESP+1)
70
71 #define IPSEC_KEY_MAX_LEN 128
72 typedef struct ipsec_key_t_
73 {
74   u8 len;
75   u8 data[IPSEC_KEY_MAX_LEN];
76 } ipsec_key_t;
77
78 /*
79  * Enable extended sequence numbers
80  * Enable Anti-replay
81  * IPsec tunnel mode if non-zero, else transport mode
82  * IPsec tunnel mode is IPv6 if non-zero,
83  * else IPv4 tunnel only valid if is_tunnel is non-zero
84  * enable UDP encapsulation for NAT traversal
85  */
86 #define foreach_ipsec_sa_flags                            \
87   _ (0, NONE, "none")                                     \
88   _ (1, USE_ESN, "esn")                                   \
89   _ (2, USE_ANTI_REPLAY, "anti-replay")                   \
90   _ (4, IS_TUNNEL, "tunnel")                              \
91   _ (8, IS_TUNNEL_V6, "tunnel-v6")                        \
92   _ (16, UDP_ENCAP, "udp-encap")                          \
93   _ (32, IS_GRE, "GRE")                                   \
94
95 typedef enum ipsec_sad_flags_t_
96 {
97 #define _(v, f, s) IPSEC_SA_FLAG_##f = v,
98   foreach_ipsec_sa_flags
99 #undef _
100 } __clib_packed ipsec_sa_flags_t;
101
102 STATIC_ASSERT (sizeof (ipsec_sa_flags_t) == 1, "IPSEC SA flags > 1 byte");
103
104 typedef struct
105 {
106   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
107
108   /* flags */
109   ipsec_sa_flags_t flags;
110
111   u8 crypto_iv_size;
112   u8 crypto_block_size;
113   u8 integ_trunc_size;
114   u32 spi;
115   u32 seq;
116   u32 seq_hi;
117   u32 last_seq;
118   u32 last_seq_hi;
119   u64 replay_window;
120
121   vnet_crypto_op_type_t crypto_enc_op_type;
122   vnet_crypto_op_type_t crypto_dec_op_type;
123   vnet_crypto_op_type_t integ_op_type;
124
125   dpo_id_t dpo[IPSEC_N_PROTOCOLS];
126
127   /* data accessed by dataplane code should be above this comment */
128     CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
129
130   union
131   {
132     ip4_header_t ip4_hdr;
133     ip6_header_t ip6_hdr;
134   };
135   udp_header_t udp_hdr;
136
137
138   fib_node_t node;
139   u32 id;
140   u32 stat_index;
141   ipsec_protocol_t protocol;
142
143   ipsec_crypto_alg_t crypto_alg;
144   ipsec_key_t crypto_key;
145
146   ipsec_integ_alg_t integ_alg;
147   ipsec_key_t integ_key;
148
149   ip46_address_t tunnel_src_addr;
150   ip46_address_t tunnel_dst_addr;
151
152   fib_node_index_t fib_entry_index;
153   u32 sibling;
154
155   u32 tx_fib_index;
156   u32 salt;
157
158   /* runtime */
159 } ipsec_sa_t;
160
161 STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline1, CLIB_CACHE_LINE_BYTES);
162
163 #define _(a,v,s)                                                        \
164   always_inline int                                                     \
165   ipsec_sa_is_set_##v (const ipsec_sa_t *sa) {                          \
166     return (sa->flags & IPSEC_SA_FLAG_##v);                             \
167   }
168 foreach_ipsec_sa_flags
169 #undef _
170 #define _(a,v,s)                                                        \
171   always_inline int                                                     \
172   ipsec_sa_set_##v (ipsec_sa_t *sa) {                                   \
173     return (sa->flags |= IPSEC_SA_FLAG_##v);                            \
174   }
175   foreach_ipsec_sa_flags
176 #undef _
177 /**
178  * @brief
179  * SA packet & bytes counters
180  */
181 extern vlib_combined_counter_main_t ipsec_sa_counters;
182
183 extern void ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len);
184
185 extern int ipsec_sa_add (u32 id,
186                          u32 spi,
187                          ipsec_protocol_t proto,
188                          ipsec_crypto_alg_t crypto_alg,
189                          const ipsec_key_t * ck,
190                          ipsec_integ_alg_t integ_alg,
191                          const ipsec_key_t * ik,
192                          ipsec_sa_flags_t flags,
193                          u32 tx_table_id,
194                          const ip46_address_t * tunnel_src_addr,
195                          const ip46_address_t * tunnel_dst_addr,
196                          u32 * sa_index);
197 extern u32 ipsec_sa_del (u32 id);
198 extern void ipsec_sa_stack (ipsec_sa_t * sa);
199 extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa,
200                                      ipsec_crypto_alg_t crypto_alg);
201 extern void ipsec_sa_set_integ_alg (ipsec_sa_t * sa,
202                                     ipsec_integ_alg_t integ_alg);
203
204 extern u8 ipsec_is_sa_used (u32 sa_index);
205 extern int ipsec_set_sa_key (u32 id,
206                              const ipsec_key_t * ck, const ipsec_key_t * ik);
207 extern u32 ipsec_get_sa_index_by_sa_id (u32 sa_id);
208
209 typedef walk_rc_t (*ipsec_sa_walk_cb_t) (ipsec_sa_t * sa, void *ctx);
210 extern void ipsec_sa_walk (ipsec_sa_walk_cb_t cd, void *ctx);
211
212 extern u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
213 extern u8 *format_ipsec_integ_alg (u8 * s, va_list * args);
214 extern u8 *format_ipsec_sa (u8 * s, va_list * args);
215 extern u8 *format_ipsec_key (u8 * s, va_list * args);
216 extern uword unformat_ipsec_crypto_alg (unformat_input_t * input,
217                                         va_list * args);
218 extern uword unformat_ipsec_integ_alg (unformat_input_t * input,
219                                        va_list * args);
220 extern uword unformat_ipsec_key (unformat_input_t * input, va_list * args);
221
222 always_inline int
223 ipsec_sa_anti_replay_check (ipsec_sa_t * sa, u32 * seqp)
224 {
225   u32 seq, diff, tl, th;
226   if ((sa->flags & IPSEC_SA_FLAG_USE_ANTI_REPLAY) == 0)
227     return 0;
228
229   seq = clib_net_to_host_u32 (*seqp);
230
231   if ((sa->flags & IPSEC_SA_FLAG_USE_ESN) == 0)
232     {
233
234       if (PREDICT_TRUE (seq > sa->last_seq))
235         return 0;
236
237       diff = sa->last_seq - seq;
238
239       if (IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE > diff)
240         return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
241       else
242         return 1;
243
244       return 0;
245     }
246
247   tl = sa->last_seq;
248   th = sa->last_seq_hi;
249   diff = tl - seq;
250
251   if (PREDICT_TRUE (tl >= (IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE - 1)))
252     {
253       if (seq >= (tl - IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE + 1))
254         {
255           sa->seq_hi = th;
256           if (seq <= tl)
257             return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
258           else
259             return 0;
260         }
261       else
262         {
263           sa->seq_hi = th + 1;
264           return 0;
265         }
266     }
267   else
268     {
269       if (seq >= (tl - IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE + 1))
270         {
271           sa->seq_hi = th - 1;
272           return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
273         }
274       else
275         {
276           sa->seq_hi = th;
277           if (seq <= tl)
278             return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
279           else
280             return 0;
281         }
282     }
283
284   return 0;
285 }
286
287 always_inline void
288 ipsec_sa_anti_replay_advance (ipsec_sa_t * sa, u32 * seqp)
289 {
290   u32 pos, seq;
291   if (PREDICT_TRUE (sa->flags & IPSEC_SA_FLAG_USE_ANTI_REPLAY) == 0)
292     return;
293
294   seq = clib_host_to_net_u32 (*seqp);
295   if (PREDICT_TRUE (sa->flags & IPSEC_SA_FLAG_USE_ESN))
296     {
297       int wrap = sa->seq_hi - sa->last_seq_hi;
298
299       if (wrap == 0 && seq > sa->last_seq)
300         {
301           pos = seq - sa->last_seq;
302           if (pos < IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
303             sa->replay_window = ((sa->replay_window) << pos) | 1;
304           else
305             sa->replay_window = 1;
306           sa->last_seq = seq;
307         }
308       else if (wrap > 0)
309         {
310           pos = ~seq + sa->last_seq + 1;
311           if (pos < IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
312             sa->replay_window = ((sa->replay_window) << pos) | 1;
313           else
314             sa->replay_window = 1;
315           sa->last_seq = seq;
316           sa->last_seq_hi = sa->seq_hi;
317         }
318       else if (wrap < 0)
319         {
320           pos = ~seq + sa->last_seq + 1;
321           sa->replay_window |= (1ULL << pos);
322         }
323       else
324         {
325           pos = sa->last_seq - seq;
326           sa->replay_window |= (1ULL << pos);
327         }
328     }
329   else
330     {
331       if (seq > sa->last_seq)
332         {
333           pos = seq - sa->last_seq;
334           if (pos < IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
335             sa->replay_window = ((sa->replay_window) << pos) | 1;
336           else
337             sa->replay_window = 1;
338           sa->last_seq = seq;
339         }
340       else
341         {
342           pos = sa->last_seq - seq;
343           sa->replay_window |= (1ULL << pos);
344         }
345     }
346 }
347
348 #endif /* __IPSEC_SPD_SA_H__ */
349
350 /*
351  * fd.io coding-style-patch-verification: ON
352  *
353  * Local Variables:
354  * eval: (c-set-style "gnu")
355  * End:
356  */