blob: 12700ccaa3975a5dd5dd1963fbb3791d63173f1c [file] [log] [blame]
Neale Ranns999c8ee2019-02-01 03:31:24 -08001/*
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>
Neale Ranns8d7c5022019-02-06 01:41:05 -080020#include <vnet/fib/fib_node.h>
Neale Ranns999c8ee2019-02-01 03:31:24 -080021
Damjan Marion1f4e1cb2019-03-28 19:19:31 +010022#define IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE (64)
23
Neale Ranns999c8ee2019-02-01 03:31:24 -080024#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
38typedef 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
55typedef 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
63typedef enum
64{
65 IPSEC_PROTOCOL_AH = 0,
66 IPSEC_PROTOCOL_ESP = 1
67} ipsec_protocol_t;
68
Neale Ranns8d7c5022019-02-06 01:41:05 -080069#define IPSEC_N_PROTOCOLS (IPSEC_PROTOCOL_ESP+1)
70
71#define IPSEC_KEY_MAX_LEN 128
72typedef 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") \
Damjan Marion1e3aa5e2019-03-28 10:58:59 +010088 _ (1, USE_ESN, "esn") \
Neale Ranns8d7c5022019-02-06 01:41:05 -080089 _ (2, USE_ANTI_REPLAY, "anti-replay") \
90 _ (4, IS_TUNNEL, "tunnel") \
91 _ (8, IS_TUNNEL_V6, "tunnel-v6") \
92 _ (16, UDP_ENCAP, "udp-encap") \
Neale Rannse524d452019-02-19 15:22:46 +000093 _ (32, IS_GRE, "GRE") \
Neale Ranns2b5ba952019-04-02 10:15:40 +000094 _ (64, IS_INBOUND, "inboud") \
Neale Ranns8d7c5022019-02-06 01:41:05 -080095
96typedef enum ipsec_sad_flags_t_
97{
98#define _(v, f, s) IPSEC_SA_FLAG_##f = v,
99 foreach_ipsec_sa_flags
100#undef _
Damjan Marion1f4e1cb2019-03-28 19:19:31 +0100101} __clib_packed ipsec_sa_flags_t;
Damjan Mariond709cbc2019-03-26 13:16:42 +0100102
103STATIC_ASSERT (sizeof (ipsec_sa_flags_t) == 1, "IPSEC SA flags > 1 byte");
Neale Ranns8d7c5022019-02-06 01:41:05 -0800104
Neale Ranns999c8ee2019-02-01 03:31:24 -0800105typedef struct
106{
Damjan Mariond709cbc2019-03-26 13:16:42 +0100107 CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800108
Damjan Mariond709cbc2019-03-26 13:16:42 +0100109 /* flags */
110 ipsec_sa_flags_t flags;
111
Damjan Marionb966e8b2019-03-20 16:07:09 +0100112 u8 crypto_iv_size;
113 u8 crypto_block_size;
Damjan Marion7c22ff72019-04-04 12:25:44 +0200114 u8 integ_icv_size;
Damjan Mariond709cbc2019-03-26 13:16:42 +0100115 u32 spi;
Neale Ranns999c8ee2019-02-01 03:31:24 -0800116 u32 seq;
117 u32 seq_hi;
118 u32 last_seq;
119 u32 last_seq_hi;
120 u64 replay_window;
Damjan Mariond709cbc2019-03-26 13:16:42 +0100121
122 vnet_crypto_op_type_t crypto_enc_op_type;
123 vnet_crypto_op_type_t crypto_dec_op_type;
124 vnet_crypto_op_type_t integ_op_type;
125
126 dpo_id_t dpo[IPSEC_N_PROTOCOLS];
127
128 /* data accessed by dataplane code should be above this comment */
129 CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
130
131 union
132 {
133 ip4_header_t ip4_hdr;
134 ip6_header_t ip6_hdr;
135 };
136 udp_header_t udp_hdr;
137
138
139 fib_node_t node;
140 u32 id;
141 u32 stat_index;
142 ipsec_protocol_t protocol;
143
144 ipsec_crypto_alg_t crypto_alg;
145 ipsec_key_t crypto_key;
146
147 ipsec_integ_alg_t integ_alg;
148 ipsec_key_t integ_key;
149
150 ip46_address_t tunnel_src_addr;
151 ip46_address_t tunnel_dst_addr;
152
153 fib_node_index_t fib_entry_index;
154 u32 sibling;
155
156 u32 tx_fib_index;
157 u32 salt;
158
159 /* runtime */
Neale Ranns999c8ee2019-02-01 03:31:24 -0800160} ipsec_sa_t;
161
Damjan Mariond709cbc2019-03-26 13:16:42 +0100162STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline1, CLIB_CACHE_LINE_BYTES);
163
164#define _(a,v,s) \
165 always_inline int \
166 ipsec_sa_is_set_##v (const ipsec_sa_t *sa) { \
167 return (sa->flags & IPSEC_SA_FLAG_##v); \
168 }
169foreach_ipsec_sa_flags
170#undef _
171#define _(a,v,s) \
172 always_inline int \
173 ipsec_sa_set_##v (ipsec_sa_t *sa) { \
174 return (sa->flags |= IPSEC_SA_FLAG_##v); \
175 }
176 foreach_ipsec_sa_flags
177#undef _
Neale Rannseba31ec2019-02-17 18:04:27 +0000178/**
179 * @brief
180 * SA packet & bytes counters
181 */
182extern vlib_combined_counter_main_t ipsec_sa_counters;
183
Neale Ranns8d7c5022019-02-06 01:41:05 -0800184extern void ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len);
185
186extern int ipsec_sa_add (u32 id,
187 u32 spi,
188 ipsec_protocol_t proto,
189 ipsec_crypto_alg_t crypto_alg,
190 const ipsec_key_t * ck,
191 ipsec_integ_alg_t integ_alg,
192 const ipsec_key_t * ik,
193 ipsec_sa_flags_t flags,
194 u32 tx_table_id,
195 const ip46_address_t * tunnel_src_addr,
196 const ip46_address_t * tunnel_dst_addr,
197 u32 * sa_index);
198extern u32 ipsec_sa_del (u32 id);
Neale Rannsb4cfd552019-02-13 02:08:06 -0800199extern void ipsec_sa_stack (ipsec_sa_t * sa);
Damjan Marionb966e8b2019-03-20 16:07:09 +0100200extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa,
201 ipsec_crypto_alg_t crypto_alg);
202extern void ipsec_sa_set_integ_alg (ipsec_sa_t * sa,
203 ipsec_integ_alg_t integ_alg);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800204
Neale Ranns999c8ee2019-02-01 03:31:24 -0800205extern u8 ipsec_is_sa_used (u32 sa_index);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800206extern int ipsec_set_sa_key (u32 id,
207 const ipsec_key_t * ck, const ipsec_key_t * ik);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800208extern u32 ipsec_get_sa_index_by_sa_id (u32 sa_id);
209
Neale Rannsb4cfd552019-02-13 02:08:06 -0800210typedef walk_rc_t (*ipsec_sa_walk_cb_t) (ipsec_sa_t * sa, void *ctx);
211extern void ipsec_sa_walk (ipsec_sa_walk_cb_t cd, void *ctx);
212
Neale Ranns999c8ee2019-02-01 03:31:24 -0800213extern u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
214extern u8 *format_ipsec_integ_alg (u8 * s, va_list * args);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800215extern u8 *format_ipsec_sa (u8 * s, va_list * args);
216extern u8 *format_ipsec_key (u8 * s, va_list * args);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800217extern uword unformat_ipsec_crypto_alg (unformat_input_t * input,
218 va_list * args);
219extern uword unformat_ipsec_integ_alg (unformat_input_t * input,
220 va_list * args);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800221extern uword unformat_ipsec_key (unformat_input_t * input, va_list * args);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800222
Damjan Marion1f4e1cb2019-03-28 19:19:31 +0100223always_inline int
224ipsec_sa_anti_replay_check (ipsec_sa_t * sa, u32 * seqp)
225{
226 u32 seq, diff, tl, th;
227 if ((sa->flags & IPSEC_SA_FLAG_USE_ANTI_REPLAY) == 0)
228 return 0;
229
230 seq = clib_net_to_host_u32 (*seqp);
231
Damjan Marion1e3aa5e2019-03-28 10:58:59 +0100232 if ((sa->flags & IPSEC_SA_FLAG_USE_ESN) == 0)
Damjan Marion1f4e1cb2019-03-28 19:19:31 +0100233 {
234
235 if (PREDICT_TRUE (seq > sa->last_seq))
236 return 0;
237
238 diff = sa->last_seq - seq;
239
240 if (IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE > diff)
241 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
242 else
243 return 1;
244
245 return 0;
246 }
247
248 tl = sa->last_seq;
249 th = sa->last_seq_hi;
250 diff = tl - seq;
251
252 if (PREDICT_TRUE (tl >= (IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE - 1)))
253 {
254 if (seq >= (tl - IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE + 1))
255 {
256 sa->seq_hi = th;
257 if (seq <= tl)
258 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
259 else
260 return 0;
261 }
262 else
263 {
264 sa->seq_hi = th + 1;
265 return 0;
266 }
267 }
268 else
269 {
270 if (seq >= (tl - IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE + 1))
271 {
272 sa->seq_hi = th - 1;
273 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
274 }
275 else
276 {
277 sa->seq_hi = th;
278 if (seq <= tl)
279 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
280 else
281 return 0;
282 }
283 }
284
285 return 0;
286}
287
288always_inline void
289ipsec_sa_anti_replay_advance (ipsec_sa_t * sa, u32 * seqp)
290{
291 u32 pos, seq;
292 if (PREDICT_TRUE (sa->flags & IPSEC_SA_FLAG_USE_ANTI_REPLAY) == 0)
293 return;
294
295 seq = clib_host_to_net_u32 (*seqp);
Damjan Marion1e3aa5e2019-03-28 10:58:59 +0100296 if (PREDICT_TRUE (sa->flags & IPSEC_SA_FLAG_USE_ESN))
Damjan Marion1f4e1cb2019-03-28 19:19:31 +0100297 {
298 int wrap = sa->seq_hi - sa->last_seq_hi;
299
300 if (wrap == 0 && seq > sa->last_seq)
301 {
302 pos = seq - sa->last_seq;
303 if (pos < IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
304 sa->replay_window = ((sa->replay_window) << pos) | 1;
305 else
306 sa->replay_window = 1;
307 sa->last_seq = seq;
308 }
309 else if (wrap > 0)
310 {
311 pos = ~seq + sa->last_seq + 1;
312 if (pos < IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
313 sa->replay_window = ((sa->replay_window) << pos) | 1;
314 else
315 sa->replay_window = 1;
316 sa->last_seq = seq;
317 sa->last_seq_hi = sa->seq_hi;
318 }
319 else if (wrap < 0)
320 {
321 pos = ~seq + sa->last_seq + 1;
322 sa->replay_window |= (1ULL << pos);
323 }
324 else
325 {
326 pos = sa->last_seq - seq;
327 sa->replay_window |= (1ULL << pos);
328 }
329 }
330 else
331 {
332 if (seq > sa->last_seq)
333 {
334 pos = seq - sa->last_seq;
335 if (pos < IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
336 sa->replay_window = ((sa->replay_window) << pos) | 1;
337 else
338 sa->replay_window = 1;
339 sa->last_seq = seq;
340 }
341 else
342 {
343 pos = sa->last_seq - seq;
344 sa->replay_window |= (1ULL << pos);
345 }
346 }
347}
348
Neale Ranns999c8ee2019-02-01 03:31:24 -0800349#endif /* __IPSEC_SPD_SA_H__ */
350
351/*
352 * fd.io coding-style-patch-verification: ON
353 *
354 * Local Variables:
355 * eval: (c-set-style "gnu")
356 * End:
357 */