crypto: introduce crypto infra
[vpp.git] / src / vnet / ipsec / esp.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 __ESP_H__
16 #define __ESP_H__
17
18 #include <vnet/ip/ip.h>
19 #include <vnet/crypto/crypto.h>
20 #include <vnet/ipsec/ipsec.h>
21
22 typedef struct
23 {
24   u32 spi;
25   u32 seq;
26   u8 data[0];
27 } esp_header_t;
28
29 typedef struct
30 {
31   u8 pad_length;
32   u8 next_header;
33 } esp_footer_t;
34
35 /* *INDENT-OFF* */
36 typedef CLIB_PACKED (struct {
37   ip4_header_t ip4;
38   esp_header_t esp;
39 }) ip4_and_esp_header_t;
40 /* *INDENT-ON* */
41
42 /* *INDENT-OFF* */
43 typedef CLIB_PACKED (struct {
44   ip4_header_t ip4;
45   udp_header_t udp;
46   esp_header_t esp;
47 }) ip4_and_udp_and_esp_header_t;
48 /* *INDENT-ON* */
49
50 /* *INDENT-OFF* */
51 typedef CLIB_PACKED (struct {
52   ip6_header_t ip6;
53   esp_header_t esp;
54 }) ip6_and_esp_header_t;
55 /* *INDENT-ON* */
56
57 #define ESP_WINDOW_SIZE         (64)
58 #define ESP_SEQ_MAX             (4294967295UL)
59
60 u8 *format_esp_header (u8 * s, va_list * args);
61
62 always_inline int
63 esp_replay_check (ipsec_sa_t * sa, u32 seq)
64 {
65   u32 diff;
66
67   if (PREDICT_TRUE (seq > sa->last_seq))
68     return 0;
69
70   diff = sa->last_seq - seq;
71
72   if (ESP_WINDOW_SIZE > diff)
73     return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
74   else
75     return 1;
76
77   return 0;
78 }
79
80 always_inline int
81 esp_replay_check_esn (ipsec_sa_t * sa, u32 seq)
82 {
83   u32 tl = sa->last_seq;
84   u32 th = sa->last_seq_hi;
85   u32 diff = tl - seq;
86
87   if (PREDICT_TRUE (tl >= (ESP_WINDOW_SIZE - 1)))
88     {
89       if (seq >= (tl - ESP_WINDOW_SIZE + 1))
90         {
91           sa->seq_hi = th;
92           if (seq <= tl)
93             return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
94           else
95             return 0;
96         }
97       else
98         {
99           sa->seq_hi = th + 1;
100           return 0;
101         }
102     }
103   else
104     {
105       if (seq >= (tl - ESP_WINDOW_SIZE + 1))
106         {
107           sa->seq_hi = th - 1;
108           return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
109         }
110       else
111         {
112           sa->seq_hi = th;
113           if (seq <= tl)
114             return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
115           else
116             return 0;
117         }
118     }
119
120   return 0;
121 }
122
123 /* TODO seq increment should be atomic to be accessed by multiple workers */
124 always_inline void
125 esp_replay_advance (ipsec_sa_t * sa, u32 seq)
126 {
127   u32 pos;
128
129   if (seq > sa->last_seq)
130     {
131       pos = seq - sa->last_seq;
132       if (pos < ESP_WINDOW_SIZE)
133         sa->replay_window = ((sa->replay_window) << pos) | 1;
134       else
135         sa->replay_window = 1;
136       sa->last_seq = seq;
137     }
138   else
139     {
140       pos = sa->last_seq - seq;
141       sa->replay_window |= (1ULL << pos);
142     }
143 }
144
145 always_inline void
146 esp_replay_advance_esn (ipsec_sa_t * sa, u32 seq)
147 {
148   int wrap = sa->seq_hi - sa->last_seq_hi;
149   u32 pos;
150
151   if (wrap == 0 && seq > sa->last_seq)
152     {
153       pos = seq - sa->last_seq;
154       if (pos < ESP_WINDOW_SIZE)
155         sa->replay_window = ((sa->replay_window) << pos) | 1;
156       else
157         sa->replay_window = 1;
158       sa->last_seq = seq;
159     }
160   else if (wrap > 0)
161     {
162       pos = ~seq + sa->last_seq + 1;
163       if (pos < ESP_WINDOW_SIZE)
164         sa->replay_window = ((sa->replay_window) << pos) | 1;
165       else
166         sa->replay_window = 1;
167       sa->last_seq = seq;
168       sa->last_seq_hi = sa->seq_hi;
169     }
170   else if (wrap < 0)
171     {
172       pos = ~seq + sa->last_seq + 1;
173       sa->replay_window |= (1ULL << pos);
174     }
175   else
176     {
177       pos = sa->last_seq - seq;
178       sa->replay_window |= (1ULL << pos);
179     }
180 }
181
182 always_inline int
183 esp_seq_advance (ipsec_sa_t * sa)
184 {
185   if (PREDICT_TRUE (sa->use_esn))
186     {
187       if (PREDICT_FALSE (sa->seq == ESP_SEQ_MAX))
188         {
189           if (PREDICT_FALSE
190               (sa->use_anti_replay && sa->seq_hi == ESP_SEQ_MAX))
191             return 1;
192           sa->seq_hi++;
193         }
194       sa->seq++;
195     }
196   else
197     {
198       if (PREDICT_FALSE (sa->use_anti_replay && sa->seq == ESP_SEQ_MAX))
199         return 1;
200       sa->seq++;
201     }
202
203   return 0;
204 }
205
206
207 always_inline unsigned int
208 hmac_calc (vlib_main_t * vm, ipsec_integ_alg_t alg, u8 * key, int key_len,
209            u8 * data, int data_len, u8 * signature, u8 use_esn, u32 seq_hi)
210 {
211   ipsec_main_t *im = &ipsec_main;
212   vnet_crypto_op_t _op, *op = &_op;
213   ASSERT (alg < IPSEC_INTEG_N_ALG);
214
215   if (PREDICT_FALSE (im->integ_algs[alg].op_type == 0))
216     return 0;
217
218   op->op = im->integ_algs[alg].op_type;
219   op->key = key;
220   op->key_len = key_len;
221   op->src = data;
222   op->len = data_len;
223   op->dst = signature;
224 #if 0
225
226   HMAC_Init_ex (ctx, key, key_len, md, NULL);
227
228   HMAC_Update (ctx, data, data_len);
229
230   if (PREDICT_TRUE (use_esn))
231     HMAC_Update (ctx, (u8 *) & seq_hi, sizeof (seq_hi));
232   HMAC_Final (ctx, signature, &len);
233
234 #endif
235   vnet_crypto_process_ops (vm, op, 1);
236   return im->integ_algs[alg].trunc_size;
237 }
238
239 #endif /* __ESP_H__ */
240
241 /*
242  * fd.io coding-style-patch-verification: ON
243  *
244  * Local Variables:
245  * eval: (c-set-style "gnu")
246  * End:
247  */