FD.io VPP  v18.04-17-g3a0d853
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 
116 
117  i_bi0 = from[0];
118  from += 1;
119  n_left_from -= 1;
120  n_left_to_next -= 1;
121 
122  next0 = AH_DECRYPT_NEXT_DROP;
123 
124  i_b0 = vlib_get_buffer (vm, i_bi0);
125  to_next[0] = i_bi0;
126  to_next += 1;
127  ih4 = vlib_buffer_get_current (i_b0);
128  ip_hdr_size = ip4_header_bytes (ih4);
129  ah0 = (ah_header_t *) ((u8 *) ih4 + ip_hdr_size);
130 
131  sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
132  sa0 = pool_elt_at_index (im->sad, sa_index0);
133 
134  seq = clib_host_to_net_u32 (ah0->seq_no);
135  /* anti-replay check */
136  //TODO UT remaining
137  if (sa0->use_anti_replay)
138  {
139  int rv = 0;
140 
141  if (PREDICT_TRUE (sa0->use_esn))
142  rv = esp_replay_check_esn (sa0, seq);
143  else
144  rv = esp_replay_check (sa0, seq);
145 
146  if (PREDICT_FALSE (rv))
147  {
148  clib_warning ("anti-replay SPI %u seq %u", sa0->spi, seq);
150  AH_DECRYPT_ERROR_REPLAY, 1);
151  to_next[0] = i_bi0;
152  to_next += 1;
153  goto trace;
154  }
155  }
156 
157 
158  sa0->total_data_size += i_b0->current_length;
159  icv_size =
161  if (PREDICT_TRUE (sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
162  {
163  u8 sig[64];
164  u8 digest[64];
165  memset (sig, 0, sizeof (sig));
166  memset (digest, 0, sizeof (digest));
167  u8 *icv =
168  vlib_buffer_get_current (i_b0) + ip_hdr_size +
169  sizeof (ah_header_t);
170  memcpy (digest, icv, icv_size);
171  memset (icv, 0, icv_size);
172 
173  if ((ih4->ip_version_and_header_length & 0xF0) == 0x40)
174  {
175  tos = ih4->tos;
176  ttl = ih4->ttl;
177  ih4->tos = 0;
178  ih4->ttl = 0;
179  ih4->checksum = 0;
180  ih4->flags_and_fragment_offset = 0;
181  } //TODO else part for IPv6
182  hmac_calc (sa0->integ_alg, sa0->integ_key, sa0->integ_key_len,
183  (u8 *) ih4, i_b0->current_length, sig, sa0->use_esn,
184  sa0->seq_hi);
185 
186  if (PREDICT_FALSE (memcmp (digest, sig, icv_size)))
187  {
189  AH_DECRYPT_ERROR_INTEG_ERROR,
190  1);
191  to_next[0] = i_bi0;
192  to_next += 1;
193  goto trace;
194  }
195 
196  //TODO UT remaining
197  if (PREDICT_TRUE (sa0->use_anti_replay))
198  {
199  if (PREDICT_TRUE (sa0->use_esn))
200  esp_replay_advance_esn (sa0, seq);
201  else
202  esp_replay_advance (sa0, seq);
203  }
204 
205  }
206 
207 
208  vlib_buffer_advance (i_b0,
209  ip_hdr_size + sizeof (ah_header_t) + icv_size);
210  i_b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
211 
212  /* transport mode */
213  if (PREDICT_FALSE (!sa0->is_tunnel && !sa0->is_tunnel_ip6))
214  {
215  tunnel_mode = 0;
216 
217  if (PREDICT_TRUE
218  ((ih4->ip_version_and_header_length & 0xF0) != 0x40))
219  {
220  if (PREDICT_TRUE
221  ((ih4->ip_version_and_header_length & 0xF0) == 0x60))
222  transport_ip6 = 1;
223  else
224  {
225  clib_warning ("next header: 0x%x", ah0->nexthdr);
227  AH_DECRYPT_ERROR_NOT_IP,
228  1);
229  goto trace;
230  }
231  }
232  }
233 
234  if (PREDICT_TRUE (tunnel_mode))
235  {
236  if (PREDICT_TRUE (ah0->nexthdr == IP_PROTOCOL_IP_IN_IP))
237  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
238  else if (ah0->nexthdr == IP_PROTOCOL_IPV6)
239  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
240  else
241  {
242  clib_warning ("next header: 0x%x", ah0->nexthdr);
244  AH_DECRYPT_ERROR_DECRYPTION_FAILED,
245  1);
246  goto trace;
247  }
248  }
249  /* transport mode */
250  else
251  {
252  if (PREDICT_FALSE (transport_ip6))
253  {
254  ih6 =
255  (ip6_header_t *) (i_b0->data +
256  sizeof (ethernet_header_t));
257  vlib_buffer_advance (i_b0, -sizeof (ip6_header_t));
258  oh6 = vlib_buffer_get_current (i_b0);
259  memmove (oh6, ih6, sizeof (ip6_header_t));
260 
261  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
262  oh6->protocol = ah0->nexthdr;
263  oh6->payload_length =
264  clib_host_to_net_u16 (vlib_buffer_length_in_chain
265  (vm, i_b0) - sizeof (ip6_header_t));
266  }
267  else
268  {
269  vlib_buffer_advance (i_b0, -sizeof (ip4_header_t));
270  oh4 = vlib_buffer_get_current (i_b0);
271  memmove (oh4, ih4, sizeof (ip4_header_t));
272 
273  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
274  oh4->ip_version_and_header_length = 0x45;
275  oh4->fragment_id = 0;
276  oh4->flags_and_fragment_offset = 0;
277  oh4->protocol = ah0->nexthdr;
278  oh4->length =
279  clib_host_to_net_u16 (vlib_buffer_length_in_chain
280  (vm, i_b0));
281  oh4->ttl = ttl;
282  oh4->tos = tos;
283  oh4->checksum = ip4_header_checksum (oh4);
284  }
285  }
286 
287  /* for IPSec-GRE tunnel next node is ipsec-gre-input */
288  if (PREDICT_FALSE
289  ((vnet_buffer (i_b0)->ipsec.flags) &
291  next0 = AH_DECRYPT_NEXT_IPSEC_GRE_INPUT;
292 
293 
294  vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
295  trace:
296  if (PREDICT_FALSE (i_b0->flags & VLIB_BUFFER_IS_TRACED))
297  {
298  i_b0->flags |= VLIB_BUFFER_IS_TRACED;
299  ah_decrypt_trace_t *tr =
300  vlib_add_trace (vm, node, i_b0, sizeof (*tr));
301  tr->integ_alg = sa0->integ_alg;
302  }
303  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
304  n_left_to_next, i_bi0, next0);
305  }
306  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
307  }
309  AH_DECRYPT_ERROR_RX_PKTS,
310  from_frame->n_vectors);
311 
312  return from_frame->n_vectors;
313 }
314 
315 
316 /* *INDENT-OFF* */
318  .function = ah_decrypt_node_fn,
319  .name = "ah-decrypt",
320  .vector_size = sizeof (u32),
321  .format_trace = format_ah_decrypt_trace,
322  .type = VLIB_NODE_TYPE_INTERNAL,
323 
324  .n_errors = ARRAY_LEN(ah_decrypt_error_strings),
325  .error_strings = ah_decrypt_error_strings,
326 
327  .n_next_nodes = AH_DECRYPT_N_NEXT,
328  .next_nodes = {
329 #define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
331 #undef _
332  },
333 };
334 /* *INDENT-ON* */
335 
337 /*
338  * fd.io coding-style-patch-verification: ON
339  *
340  * Local Variables:
341  * eval: (c-set-style "gnu")
342  * End:
343  */
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:79
ipsec_proto_main_integ_alg_t * ipsec_proto_main_integ_algs
Definition: esp.h:93
#define PREDICT_TRUE(x)
Definition: clib.h:106
static void esp_replay_advance(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:167
static int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:227
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:323
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:145
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:107
ah_decrypt_error_t
Definition: ah_decrypt.c:49
u32 spi
Definition: ipsec.h:114
u32 seq_hi
Definition: ipsec.h:137
u8 integ_key[128]
Definition: ipsec.h:123
static void esp_replay_advance_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:188
ipsec_main_t ipsec_main
Definition: ipsec.c:28
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:317
static u8 * format_ah_decrypt_trace(u8 *s, va_list *args)
Definition: ah_decrypt.c:70
#define foreach_ah_decrypt_error
Definition: ah_decrypt.c:41
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
ipsec_integ_alg_t
Definition: ipsec.h:97
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:108
u8 is_tunnel_ip6
Definition: ipsec.h:129
static int esp_replay_check_esn(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:123
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:209
#define PREDICT_FALSE(x)
Definition: clib.h:105
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:1166
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u16 n_vectors
Definition: node.h:344
vlib_main_t * vm
Definition: buffer.c:294
#define clib_warning(format, args...)
Definition: error.h:59
#define ARRAY_LEN(x)
Definition: clib.h:59
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:454
#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:456
static int esp_replay_check(ipsec_sa_t *sa, u32 seq)
Definition: esp.h:105
unsigned int u32
Definition: types.h:88
ipsec_sa_t * sad
Definition: ipsec.h:260
u64 total_data_size
Definition: ipsec.h:143
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:222
u64 uword
Definition: types.h:112
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:55
u8 * format_ipsec_integ_alg(u8 *s, va_list *args)
Definition: ipsec_format.c:90
Definition: defs.h:47
unsigned char u8
Definition: types.h:56
ah_decrypt_next_t
Definition: ah_decrypt.c:33
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:372
Definition: ah.h:27
u8 data[0]
Packet data.
Definition: buffer.h:179
ipsec_proto_main_t ipsec_proto_main
Definition: esp_encrypt.c:25
u8 ip_version_and_header_length
Definition: ip4_packet.h:132
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:111
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:57
#define IPSEC_FLAG_IPSEC_GRE_TUNNEL
Definition: ipsec.h:21
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:239