FD.io VPP  v19.01.3-6-g70449b9b9
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 #define foreach_ah_decrypt_error \
41  _ (RX_PKTS, "AH pkts received") \
42  _ (DECRYPTION_FAILED, "AH decryption failed") \
43  _ (INTEG_ERROR, "Integrity check failed") \
44  _ (REPLAY, "SA replayed packet")
45 
46 typedef enum
47 {
48 #define _(sym,str) AH_DECRYPT_ERROR_##sym,
50 #undef _
53 
54 static char *ah_decrypt_error_strings[] = {
55 #define _(sym,string) string,
57 #undef _
58 };
59 
60 typedef struct
61 {
65 
66 /* packet trace format function */
67 static u8 *
68 format_ah_decrypt_trace (u8 * s, va_list * args)
69 {
70  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
71  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
72  ah_decrypt_trace_t *t = va_arg (*args, ah_decrypt_trace_t *);
73 
74  s = format (s, "ah: integrity %U seq-num %d",
76  return s;
77 }
78 
81  vlib_node_runtime_t * node, vlib_frame_t * from_frame,
82  int is_ip6)
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 ip_hdr_size = 0;
111  u8 tos = 0;
112  u8 ttl = 0;
113  u32 ip_version_traffic_class_and_flow_label = 0;
114  u8 hop_limit = 0;
115  u8 nexthdr = 0;
116  u8 icv_padding_len = 0;
117 
118 
119  i_bi0 = from[0];
120  from += 1;
121  n_left_from -= 1;
122  n_left_to_next -= 1;
123 
124  next0 = AH_DECRYPT_NEXT_DROP;
125 
126  i_b0 = vlib_get_buffer (vm, i_bi0);
127  to_next[0] = i_bi0;
128  to_next += 1;
129  ih4 = vlib_buffer_get_current (i_b0);
130  ih6 = vlib_buffer_get_current (i_b0);
131  sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
132  sa0 = pool_elt_at_index (im->sad, sa_index0);
133 
134  if (is_ip6)
135  {
136  ip6_ext_header_t *prev = NULL;
137  ip6_ext_header_find_t (ih6, prev, ah0, IP_PROTOCOL_IPSEC_AH);
138  ip_hdr_size = sizeof (ip6_header_t);
139  ASSERT ((u8 *) ah0 - (u8 *) ih6 == ip_hdr_size);
140  }
141  else
142  {
143  ip_hdr_size = ip4_header_bytes (ih4);
144  ah0 = (ah_header_t *) ((u8 *) ih4 + ip_hdr_size);
145  }
146 
147  seq = clib_host_to_net_u32 (ah0->seq_no);
148 
149  /* anti-replay check */
150  if (sa0->use_anti_replay)
151  {
152  int rv = 0;
153 
154  if (PREDICT_TRUE (sa0->use_esn))
155  rv = esp_replay_check_esn (sa0, seq);
156  else
157  rv = esp_replay_check (sa0, seq);
158 
159  if (PREDICT_FALSE (rv))
160  {
162  AH_DECRYPT_ERROR_REPLAY, 1);
163  goto trace;
164  }
165  }
166 
167 
168  sa0->total_data_size += i_b0->current_length;
169  icv_size =
171  if (PREDICT_TRUE (sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
172  {
173  u8 sig[64];
174  u8 digest[64];
175  clib_memset (sig, 0, sizeof (sig));
176  clib_memset (digest, 0, sizeof (digest));
177  u8 *icv = ah0->auth_data;
178  memcpy (digest, icv, icv_size);
179  clib_memset (icv, 0, icv_size);
180 
181  if (is_ip6)
182  {
183  ip_version_traffic_class_and_flow_label =
185  hop_limit = ih6->hop_limit;
187  ih6->hop_limit = 0;
188  nexthdr = ah0->nexthdr;
189  icv_padding_len =
190  ah_calc_icv_padding_len (icv_size, 1 /* is_ipv6 */ );
191  }
192  else
193  {
194  tos = ih4->tos;
195  ttl = ih4->ttl;
196  ih4->tos = 0;
197  ih4->ttl = 0;
198  ih4->checksum = 0;
199  ih4->flags_and_fragment_offset = 0;
200  icv_padding_len =
201  ah_calc_icv_padding_len (icv_size, 0 /* is_ipv6 */ );
202  }
203  hmac_calc (sa0->integ_alg, sa0->integ_key, sa0->integ_key_len,
204  (u8 *) ih4, i_b0->current_length, sig, sa0->use_esn,
205  sa0->seq_hi);
206 
207  if (PREDICT_FALSE (memcmp (digest, sig, icv_size)))
208  {
210  AH_DECRYPT_ERROR_INTEG_ERROR,
211  1);
212  goto trace;
213  }
214 
215  if (PREDICT_TRUE (sa0->use_anti_replay))
216  {
217  if (PREDICT_TRUE (sa0->use_esn))
218  esp_replay_advance_esn (sa0, seq);
219  else
220  esp_replay_advance (sa0, seq);
221  }
222 
223  }
224 
225  vlib_buffer_advance (i_b0,
226  ip_hdr_size + sizeof (ah_header_t) + icv_size +
227  icv_padding_len);
228  i_b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
229 
230  if (PREDICT_TRUE (sa0->is_tunnel))
231  { /* tunnel mode */
232  if (PREDICT_TRUE (ah0->nexthdr == IP_PROTOCOL_IP_IN_IP))
233  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
234  else if (ah0->nexthdr == IP_PROTOCOL_IPV6)
235  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
236  else
237  {
239  AH_DECRYPT_ERROR_DECRYPTION_FAILED,
240  1);
241  goto trace;
242  }
243  }
244  else
245  { /* transport mode */
246  if (is_ip6)
247  {
248  vlib_buffer_advance (i_b0, -sizeof (ip6_header_t));
249  oh6 = vlib_buffer_get_current (i_b0);
250  memmove (oh6, ih6, sizeof (ip6_header_t));
251 
252  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
253  oh6->protocol = nexthdr;
254  oh6->hop_limit = hop_limit;
255  oh6->ip_version_traffic_class_and_flow_label =
256  ip_version_traffic_class_and_flow_label;
257  oh6->payload_length =
258  clib_host_to_net_u16 (vlib_buffer_length_in_chain
259  (vm, i_b0) - sizeof (ip6_header_t));
260  }
261  else
262  {
263  vlib_buffer_advance (i_b0, -sizeof (ip4_header_t));
264  oh4 = vlib_buffer_get_current (i_b0);
265  memmove (oh4, ih4, sizeof (ip4_header_t));
266 
267  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
268  oh4->ip_version_and_header_length = 0x45;
269  oh4->fragment_id = 0;
270  oh4->flags_and_fragment_offset = 0;
271  oh4->protocol = ah0->nexthdr;
272  oh4->length =
273  clib_host_to_net_u16 (vlib_buffer_length_in_chain
274  (vm, i_b0));
275  oh4->ttl = ttl;
276  oh4->tos = tos;
277  oh4->checksum = ip4_header_checksum (oh4);
278  }
279  }
280 
281  /* for IPSec-GRE tunnel next node is ipsec-gre-input */
282  if (PREDICT_FALSE
283  ((vnet_buffer (i_b0)->ipsec.flags) &
285  next0 = AH_DECRYPT_NEXT_IPSEC_GRE_INPUT;
286 
287 
288  vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
289  trace:
290  if (PREDICT_FALSE (i_b0->flags & VLIB_BUFFER_IS_TRACED))
291  {
292  i_b0->flags |= VLIB_BUFFER_IS_TRACED;
293  ah_decrypt_trace_t *tr =
294  vlib_add_trace (vm, node, i_b0, sizeof (*tr));
295  tr->integ_alg = sa0->integ_alg;
296  tr->seq_num = seq;
297  }
298  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
299  n_left_to_next, i_bi0, next0);
300  }
301  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
302  }
303  vlib_node_increment_counter (vm, node->node_index, AH_DECRYPT_ERROR_RX_PKTS,
304  from_frame->n_vectors);
305 
306  return from_frame->n_vectors;
307 }
308 
310  vlib_node_runtime_t * node,
311  vlib_frame_t * from_frame)
312 {
313  return ah_decrypt_inline (vm, node, from_frame, 0 /* is_ip6 */ );
314 }
315 
316 /* *INDENT-OFF* */
318  .name = "ah4-decrypt",
319  .vector_size = sizeof (u32),
320  .format_trace = format_ah_decrypt_trace,
321  .type = VLIB_NODE_TYPE_INTERNAL,
322 
323  .n_errors = ARRAY_LEN(ah_decrypt_error_strings),
324  .error_strings = ah_decrypt_error_strings,
325 
326  .n_next_nodes = AH_DECRYPT_N_NEXT,
327  .next_nodes = {
328 #define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
330 #undef _
331  },
332 };
333 /* *INDENT-ON* */
334 
336  vlib_node_runtime_t * node,
337  vlib_frame_t * from_frame)
338 {
339  return ah_decrypt_inline (vm, node, from_frame, 1 /* is_ip6 */ );
340 }
341 
342 /* *INDENT-OFF* */
344  .name = "ah6-decrypt",
345  .vector_size = sizeof (u32),
346  .format_trace = format_ah_decrypt_trace,
347  .type = VLIB_NODE_TYPE_INTERNAL,
348 
349  .n_errors = ARRAY_LEN(ah_decrypt_error_strings),
350  .error_strings = ah_decrypt_error_strings,
351 
352  .n_next_nodes = AH_DECRYPT_N_NEXT,
353  .next_nodes = {
354 #define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
356 #undef _
357  },
358 };
359 /* *INDENT-ON* */
360 
361 /*
362  * fd.io coding-style-patch-verification: ON
363  *
364  * Local Variables:
365  * eval: (c-set-style "gnu")
366  * End:
367  */
static char * ah_decrypt_error_strings[]
Definition: ah_decrypt.c:54
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:862
#define CLIB_UNUSED(x)
Definition: clib.h:82
ipsec_proto_main_integ_alg_t * ipsec_proto_main_integ_algs
Definition: ipsec.h:343
#define PREDICT_TRUE(x)
Definition: clib.h:112
static void esp_replay_advance(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:124
#define NULL
Definition: clib.h:58
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
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:280
ipsec_integ_alg_t integ_alg
Definition: ipsec.h:129
static uword ah_decrypt_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, int is_ip6)
Definition: ah_decrypt.c:80
u8 is_tunnel
Definition: ipsec.h:136
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u16 flags_and_fragment_offset
Definition: ip4_packet.h:151
#define VLIB_NODE_FN(node)
Definition: node.h:201
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:267
ah_decrypt_error_t
Definition: ah_decrypt.c:46
unsigned char u8
Definition: types.h:56
ipsec_proto_main_t ipsec_proto_main
Definition: esp_encrypt.c:26
u32 seq_hi
Definition: ipsec.h:147
vlib_node_registration_t ah6_decrypt_node
(constructor) VLIB_REGISTER_NODE (ah6_decrypt_node)
Definition: ah_decrypt.c:343
u8 integ_key[128]
Definition: ipsec.h:131
static void esp_replay_advance_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:145
ipsec_main_t ipsec_main
Definition: ipsec.c:30
unsigned int seq_no
Definition: ah.h:33
#define always_inline
Definition: clib.h:98
u8 use_esn
Definition: ipsec.h:133
unsigned int u32
Definition: types.h:88
static u8 * format_ah_decrypt_trace(u8 *s, va_list *args)
Definition: ah_decrypt.c:68
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:40
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:511
ipsec_integ_alg_t
Definition: ipsec.h:105
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:114
static int esp_replay_check_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:80
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:214
#define PREDICT_FALSE(x)
Definition: clib.h:111
unsigned char nexthdr
Definition: ah.h:29
u32 node_index
Node index.
Definition: node.h:518
#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:338
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:420
vlib_main_t * vm
Definition: buffer.c:301
vlib_node_registration_t ah4_decrypt_node
(constructor) VLIB_REGISTER_NODE (ah4_decrypt_node)
Definition: ah_decrypt.c:317
#define ARRAY_LEN(x)
Definition: clib.h:62
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:452
#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:537
#define ASSERT(truth)
static int esp_replay_check(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:62
ipsec_sa_t * sad
Definition: ipsec.h:353
u64 total_data_size
Definition: ipsec.h:153
u8 integ_key_len
Definition: ipsec.h:130
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:233
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:244
#define vnet_buffer(b)
Definition: buffer.h:368
Definition: ah.h:27
#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:235
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:117
u8 use_anti_replay
Definition: ipsec.h:134
ipsec_integ_alg_t integ_alg
Definition: ah_decrypt.c:62
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
#define IPSEC_FLAG_IPSEC_GRE_TUNNEL
Definition: ipsec.h:28
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:247