FD.io VPP  v18.10-32-g1161dda
Vector Packet Processing
ah_decrypt.c
Go to the documentation of this file.
1 /*
2  * ah_decrypt.c : IPSec AH decrypt node
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
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 
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 
22 #include <vnet/ipsec/ipsec.h>
23 #include <vnet/ipsec/esp.h>
24 #include <vnet/ipsec/ah.h>
25 
26 #define foreach_ah_decrypt_next \
27 _(DROP, "error-drop") \
28 _(IP4_INPUT, "ip4-input") \
29 _(IP6_INPUT, "ip6-input") \
30 _(IPSEC_GRE_INPUT, "ipsec-gre-input")
31 
32 #define _(v, s) AH_DECRYPT_NEXT_##v,
33 typedef enum
34 {
36 #undef _
39 
40 
41 #define foreach_ah_decrypt_error \
42  _(RX_PKTS, "AH pkts received") \
43  _(DECRYPTION_FAILED, "AH decryption failed") \
44  _(INTEG_ERROR, "Integrity check failed") \
45  _(REPLAY, "SA replayed packet") \
46  _(NOT_IP, "Not IP packet (dropped)")
47 
48 
49 typedef enum
50 {
51 #define _(sym,str) AH_DECRYPT_ERROR_##sym,
53 #undef _
56 
57 static char *ah_decrypt_error_strings[] = {
58 #define _(sym,string) string,
60 #undef _
61 };
62 
63 typedef struct
64 {
67 
68 /* packet trace format function */
69 static u8 *
70 format_ah_decrypt_trace (u8 * s, va_list * args)
71 {
72  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
73  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
74  ah_decrypt_trace_t *t = va_arg (*args, ah_decrypt_trace_t *);
75 
76  s = format (s, "ah: integrity %U", format_ipsec_integ_alg, t->integ_alg);
77  return s;
78 }
79 
80 static uword
82  vlib_node_runtime_t * node, vlib_frame_t * from_frame)
83 {
84  u32 n_left_from, *from, next_index, *to_next;
85  ipsec_main_t *im = &ipsec_main;
87  from = vlib_frame_vector_args (from_frame);
88  n_left_from = from_frame->n_vectors;
89  int icv_size = 0;
90 
91  next_index = node->cached_next_index;
92 
93  while (n_left_from > 0)
94  {
95  u32 n_left_to_next;
96 
97  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
98 
99  while (n_left_from > 0 && n_left_to_next > 0)
100  {
101  u32 i_bi0;
102  u32 next0;
103  vlib_buffer_t *i_b0;
104  ah_header_t *ah0;
105  ipsec_sa_t *sa0;
106  u32 sa_index0 = ~0;
107  u32 seq;
108  ip4_header_t *ih4 = 0, *oh4 = 0;
109  ip6_header_t *ih6 = 0, *oh6 = 0;
110  u8 tunnel_mode = 1;
111  u8 transport_ip6 = 0;
112  u8 ip_hdr_size = 0;
113  u8 tos = 0;
114  u8 ttl = 0;
115  u32 ip_version_traffic_class_and_flow_label = 0;
116  u8 hop_limit = 0;
117  u8 nexthdr = 0;
118  u8 icv_padding_len = 0;
119 
120 
121  i_bi0 = from[0];
122  from += 1;
123  n_left_from -= 1;
124  n_left_to_next -= 1;
125 
126  next0 = AH_DECRYPT_NEXT_DROP;
127 
128  i_b0 = vlib_get_buffer (vm, i_bi0);
129  to_next[0] = i_bi0;
130  to_next += 1;
131  ih4 = vlib_buffer_get_current (i_b0);
132  ih6 = vlib_buffer_get_current (i_b0);
133  sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
134  sa0 = pool_elt_at_index (im->sad, sa_index0);
135 
136  if ((ih4->ip_version_and_header_length & 0xF0) == 0x40)
137  {
138  ip_hdr_size = ip4_header_bytes (ih4);
139  ah0 = (ah_header_t *) ((u8 *) ih4 + ip_hdr_size);
140  }
141  else if ((ih4->ip_version_and_header_length & 0xF0) == 0x60)
142  {
143  ip6_ext_header_t *prev = NULL;
144  ip6_ext_header_find_t (ih6, prev, ah0, IP_PROTOCOL_IPSEC_AH);
145  ip_hdr_size = sizeof (ip6_header_t);
146  ASSERT ((u8 *) ah0 - (u8 *) ih6 == ip_hdr_size);
147  }
148  else
149  {
151  AH_DECRYPT_ERROR_NOT_IP, 1);
152  goto trace;
153  }
154 
155  seq = clib_host_to_net_u32 (ah0->seq_no);
156  /* anti-replay check */
157  //TODO UT remaining
158  if (sa0->use_anti_replay)
159  {
160  int rv = 0;
161 
162  if (PREDICT_TRUE (sa0->use_esn))
163  rv = esp_replay_check_esn (sa0, seq);
164  else
165  rv = esp_replay_check (sa0, seq);
166 
167  if (PREDICT_FALSE (rv))
168  {
170  AH_DECRYPT_ERROR_REPLAY, 1);
171  goto trace;
172  }
173  }
174 
175 
176  sa0->total_data_size += i_b0->current_length;
177  icv_size =
179  if (PREDICT_TRUE (sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
180  {
181  u8 sig[64];
182  u8 digest[64];
183  memset (sig, 0, sizeof (sig));
184  memset (digest, 0, sizeof (digest));
185  u8 *icv = ah0->auth_data;
186  memcpy (digest, icv, icv_size);
187  memset (icv, 0, icv_size);
188 
189  if ((ih4->ip_version_and_header_length & 0xF0) == 0x40)
190  {
191  tos = ih4->tos;
192  ttl = ih4->ttl;
193  ih4->tos = 0;
194  ih4->ttl = 0;
195  ih4->checksum = 0;
196  ih4->flags_and_fragment_offset = 0;
197  icv_padding_len =
198  ah_calc_icv_padding_len (icv_size, 0 /* is_ipv6 */ );
199  }
200  else
201  {
202  ip_version_traffic_class_and_flow_label =
204  hop_limit = ih6->hop_limit;
206  ih6->hop_limit = 0;
207  nexthdr = ah0->nexthdr;
208  icv_padding_len =
209  ah_calc_icv_padding_len (icv_size, 1 /* is_ipv6 */ );
210  }
211  hmac_calc (sa0->integ_alg, sa0->integ_key, sa0->integ_key_len,
212  (u8 *) ih4, i_b0->current_length, sig, sa0->use_esn,
213  sa0->seq_hi);
214 
215  if (PREDICT_FALSE (memcmp (digest, sig, icv_size)))
216  {
218  AH_DECRYPT_ERROR_INTEG_ERROR,
219  1);
220  goto trace;
221  }
222 
223  //TODO UT remaining
224  if (PREDICT_TRUE (sa0->use_anti_replay))
225  {
226  if (PREDICT_TRUE (sa0->use_esn))
227  esp_replay_advance_esn (sa0, seq);
228  else
229  esp_replay_advance (sa0, seq);
230  }
231 
232  }
233 
234  vlib_buffer_advance (i_b0,
235  ip_hdr_size + sizeof (ah_header_t) + icv_size +
236  icv_padding_len);
237  i_b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
238 
239  /* transport mode */
240  if (PREDICT_FALSE (!sa0->is_tunnel && !sa0->is_tunnel_ip6))
241  {
242  tunnel_mode = 0;
243 
244  if (PREDICT_TRUE
245  ((ih4->ip_version_and_header_length & 0xF0) != 0x40))
246  {
247  if (PREDICT_TRUE
248  ((ih4->ip_version_and_header_length & 0xF0) == 0x60))
249  transport_ip6 = 1;
250  else
251  {
252  clib_warning ("next header: 0x%x", ah0->nexthdr);
254  AH_DECRYPT_ERROR_NOT_IP,
255  1);
256  goto trace;
257  }
258  }
259  }
260 
261  if (PREDICT_TRUE (tunnel_mode))
262  {
263  if (PREDICT_TRUE (ah0->nexthdr == IP_PROTOCOL_IP_IN_IP))
264  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
265  else if (ah0->nexthdr == IP_PROTOCOL_IPV6)
266  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
267  else
268  {
269  clib_warning ("next header: 0x%x", ah0->nexthdr);
271  AH_DECRYPT_ERROR_DECRYPTION_FAILED,
272  1);
273  goto trace;
274  }
275  }
276  /* transport mode */
277  else
278  {
279  if (PREDICT_FALSE (transport_ip6))
280  {
281  vlib_buffer_advance (i_b0, -sizeof (ip6_header_t));
282  oh6 = vlib_buffer_get_current (i_b0);
283  memmove (oh6, ih6, sizeof (ip6_header_t));
284 
285  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
286  oh6->protocol = nexthdr;
287  oh6->hop_limit = hop_limit;
288  oh6->ip_version_traffic_class_and_flow_label =
289  ip_version_traffic_class_and_flow_label;
290  oh6->payload_length =
291  clib_host_to_net_u16 (vlib_buffer_length_in_chain
292  (vm, i_b0) - sizeof (ip6_header_t));
293  }
294  else
295  {
296  vlib_buffer_advance (i_b0, -sizeof (ip4_header_t));
297  oh4 = vlib_buffer_get_current (i_b0);
298  memmove (oh4, ih4, sizeof (ip4_header_t));
299 
300  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
301  oh4->ip_version_and_header_length = 0x45;
302  oh4->fragment_id = 0;
303  oh4->flags_and_fragment_offset = 0;
304  oh4->protocol = ah0->nexthdr;
305  oh4->length =
306  clib_host_to_net_u16 (vlib_buffer_length_in_chain
307  (vm, i_b0));
308  oh4->ttl = ttl;
309  oh4->tos = tos;
310  oh4->checksum = ip4_header_checksum (oh4);
311  }
312  }
313 
314  /* for IPSec-GRE tunnel next node is ipsec-gre-input */
315  if (PREDICT_FALSE
316  ((vnet_buffer (i_b0)->ipsec.flags) &
318  next0 = AH_DECRYPT_NEXT_IPSEC_GRE_INPUT;
319 
320 
321  vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
322  trace:
323  if (PREDICT_FALSE (i_b0->flags & VLIB_BUFFER_IS_TRACED))
324  {
325  i_b0->flags |= VLIB_BUFFER_IS_TRACED;
326  ah_decrypt_trace_t *tr =
327  vlib_add_trace (vm, node, i_b0, sizeof (*tr));
328  tr->integ_alg = sa0->integ_alg;
329  }
330  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
331  n_left_to_next, i_bi0, next0);
332  }
333  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
334  }
336  AH_DECRYPT_ERROR_RX_PKTS,
337  from_frame->n_vectors);
338 
339  return from_frame->n_vectors;
340 }
341 
342 
343 /* *INDENT-OFF* */
345  .function = ah_decrypt_node_fn,
346  .name = "ah-decrypt",
347  .vector_size = sizeof (u32),
348  .format_trace = format_ah_decrypt_trace,
349  .type = VLIB_NODE_TYPE_INTERNAL,
350 
351  .n_errors = ARRAY_LEN(ah_decrypt_error_strings),
352  .error_strings = ah_decrypt_error_strings,
353 
354  .n_next_nodes = AH_DECRYPT_N_NEXT,
355  .next_nodes = {
356 #define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
358 #undef _
359  },
360 };
361 /* *INDENT-ON* */
362 
364 /*
365  * fd.io coding-style-patch-verification: ON
366  *
367  * Local Variables:
368  * eval: (c-set-style "gnu")
369  * End:
370  */
static char * ah_decrypt_error_strings[]
Definition: ah_decrypt.c:57
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:862
#define CLIB_UNUSED(x)
Definition: clib.h:81
ipsec_proto_main_integ_alg_t * ipsec_proto_main_integ_algs
Definition: esp.h:101
#define PREDICT_TRUE(x)
Definition: clib.h:108
static void esp_replay_advance(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:175
#define NULL
Definition: clib.h:57
static unsigned int hmac_calc(ipsec_integ_alg_t alg, u8 *key, int key_len, u8 *data, int data_len, u8 *signature, u8 use_esn, u32 seq_hi)
Definition: esp.h:331
ipsec_integ_alg_t integ_alg
Definition: ipsec.h:121
u8 is_tunnel
Definition: ipsec.h:128
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u16 flags_and_fragment_offset
Definition: ip4_packet.h:150
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:263
ah_decrypt_error_t
Definition: ah_decrypt.c:49
unsigned char u8
Definition: types.h:56
u32 seq_hi
Definition: ipsec.h:138
memset(h->entries, 0, sizeof(h->entries[0])*entries)
u8 integ_key[128]
Definition: ipsec.h:123
static void esp_replay_advance_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:196
ipsec_main_t ipsec_main
Definition: ipsec.c:30
unsigned int seq_no
Definition: ah.h:33
static uword ah_decrypt_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: ah_decrypt.c:81
u8 use_esn
Definition: ipsec.h:125
vlib_node_registration_t ah_decrypt_node
(constructor) VLIB_REGISTER_NODE (ah_decrypt_node)
Definition: ah_decrypt.c:344
unsigned int u32
Definition: types.h:88
static u8 * format_ah_decrypt_trace(u8 *s, va_list *args)
Definition: ah_decrypt.c:70
unsigned char auth_data[0]
Definition: ah.h:34
static u8 ah_calc_icv_padding_len(u8 icv_size, int is_ipv6)
Definition: ah.h:53
#define foreach_ah_decrypt_error
Definition: ah_decrypt.c:41
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:209
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:464
ipsec_integ_alg_t
Definition: ipsec.h:97
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
u8 is_tunnel_ip6
Definition: ipsec.h:129
static int esp_replay_check_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:131
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:205
#define PREDICT_FALSE(x)
Definition: clib.h:107
unsigned char nexthdr
Definition: ah.h:29
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1176
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
u16 n_vectors
Definition: node.h:401
vlib_main_t * vm
Definition: buffer.c:294
#define clib_warning(format, args...)
Definition: error.h:59
#define ARRAY_LEN(x)
Definition: clib.h:61
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:455
#define foreach_ah_decrypt_next
Definition: ah_decrypt.c:26
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:513
#define ASSERT(truth)
static int esp_replay_check(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:113
ipsec_sa_t * sad
Definition: ipsec.h:265
u64 total_data_size
Definition: ipsec.h:144
u8 integ_key_len
Definition: ipsec.h:122
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:218
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
u8 * format_ipsec_integ_alg(u8 *s, va_list *args)
Definition: ipsec_format.c:90
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:365
Definition: defs.h:47
ah_decrypt_next_t
Definition: ah_decrypt.c:33
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define vnet_buffer(b)
Definition: buffer.h:344
Definition: ah.h:27
ipsec_proto_main_t ipsec_proto_main
Definition: esp_encrypt.c:26
#define ip6_ext_header_find_t(i, p, m, t)
Definition: ip6_packet.h:534
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:234
u8 ip_version_and_header_length
Definition: ip4_packet.h:137
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:116
u8 use_anti_replay
Definition: ipsec.h:126
ipsec_integ_alg_t integ_alg
Definition: ah_decrypt.c:65
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:58
#define IPSEC_FLAG_IPSEC_GRE_TUNNEL
Definition: ipsec.h:21
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:246