blob: 10f2f2df88a5bba10c95c6ffbcfc9a76b69c676b [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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 */
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +000015#ifndef __ESP_H__
16#define __ESP_H__
Ed Warnickecb9cada2015-12-08 15:45:58 -070017
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010018#include <vnet/ip/ip.h>
19#include <vnet/ipsec/ipsec.h>
20
Ed Warnickecb9cada2015-12-08 15:45:58 -070021#include <openssl/hmac.h>
22#include <openssl/rand.h>
23#include <openssl/evp.h>
24
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070025typedef struct
26{
Ed Warnickecb9cada2015-12-08 15:45:58 -070027 u32 spi;
28 u32 seq;
29 u8 data[0];
30} esp_header_t;
31
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070032typedef struct
33{
Ed Warnickecb9cada2015-12-08 15:45:58 -070034 u8 pad_length;
35 u8 next_header;
36} esp_footer_t;
37
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070038/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070039typedef CLIB_PACKED (struct {
40 ip4_header_t ip4;
41 esp_header_t esp;
42}) ip4_and_esp_header_t;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070043/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070045/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070046typedef CLIB_PACKED (struct {
47 ip6_header_t ip6;
48 esp_header_t esp;
49}) ip6_and_esp_header_t;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070050/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070052typedef struct
53{
54 const EVP_CIPHER *type;
“mukeshyadav1984”72454dd2017-11-28 10:52:34 -080055 u8 iv_size;
56 u8 block_size;
“mukeshyadav1984”430ac932017-11-23 02:39:33 -080057} ipsec_proto_main_crypto_alg_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070058
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070059typedef struct
60{
61 const EVP_MD *md;
Ed Warnickecb9cada2015-12-08 15:45:58 -070062 u8 trunc_size;
“mukeshyadav1984”430ac932017-11-23 02:39:33 -080063} ipsec_proto_main_integ_alg_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070064
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070065typedef struct
66{
67 CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
Marco Varlesef616d102017-11-09 15:16:20 +010068#if OPENSSL_VERSION_NUMBER >= 0x10100000L
69 EVP_CIPHER_CTX *encrypt_ctx;
70#else
Matthew Smith29d85102016-05-01 14:52:08 -050071 EVP_CIPHER_CTX encrypt_ctx;
Marco Varlesef616d102017-11-09 15:16:20 +010072#endif
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070073 CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
Marco Varlesef616d102017-11-09 15:16:20 +010074#if OPENSSL_VERSION_NUMBER >= 0x10100000L
75 EVP_CIPHER_CTX *decrypt_ctx;
76#else
Matthew Smith29d85102016-05-01 14:52:08 -050077 EVP_CIPHER_CTX decrypt_ctx;
Marco Varlesef616d102017-11-09 15:16:20 +010078#endif
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070079 CLIB_CACHE_LINE_ALIGN_MARK (cacheline2);
Marco Varlesef616d102017-11-09 15:16:20 +010080#if OPENSSL_VERSION_NUMBER >= 0x10100000L
81 HMAC_CTX *hmac_ctx;
82#else
Matthew Smith29d85102016-05-01 14:52:08 -050083 HMAC_CTX hmac_ctx;
Marco Varlesef616d102017-11-09 15:16:20 +010084#endif
Matthew Smith29d85102016-05-01 14:52:08 -050085 ipsec_crypto_alg_t last_encrypt_alg;
86 ipsec_crypto_alg_t last_decrypt_alg;
87 ipsec_integ_alg_t last_integ_alg;
“mukeshyadav1984”430ac932017-11-23 02:39:33 -080088} ipsec_proto_main_per_thread_data_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070089
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070090typedef struct
91{
“mukeshyadav1984”430ac932017-11-23 02:39:33 -080092 ipsec_proto_main_crypto_alg_t *ipsec_proto_main_crypto_algs;
93 ipsec_proto_main_integ_alg_t *ipsec_proto_main_integ_algs;
94 ipsec_proto_main_per_thread_data_t *per_thread_data;
95} ipsec_proto_main_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070096
“mukeshyadav1984”430ac932017-11-23 02:39:33 -080097extern ipsec_proto_main_t ipsec_proto_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +000099#define ESP_WINDOW_SIZE (64)
100#define ESP_SEQ_MAX (4294967295UL)
101
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100102u8 *format_esp_header (u8 * s, va_list * args);
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000103
104always_inline int
105esp_replay_check (ipsec_sa_t * sa, u32 seq)
106{
107 u32 diff;
108
109 if (PREDICT_TRUE (seq > sa->last_seq))
110 return 0;
111
112 diff = sa->last_seq - seq;
113
114 if (ESP_WINDOW_SIZE > diff)
115 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
116 else
117 return 1;
118
119 return 0;
120}
121
122always_inline int
123esp_replay_check_esn (ipsec_sa_t * sa, u32 seq)
124{
125 u32 tl = sa->last_seq;
126 u32 th = sa->last_seq_hi;
127 u32 diff = tl - seq;
128
129 if (PREDICT_TRUE (tl >= (ESP_WINDOW_SIZE - 1)))
130 {
131 if (seq >= (tl - ESP_WINDOW_SIZE + 1))
132 {
133 sa->seq_hi = th;
134 if (seq <= tl)
135 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
136 else
137 return 0;
138 }
139 else
140 {
141 sa->seq_hi = th + 1;
142 return 0;
143 }
144 }
145 else
146 {
147 if (seq >= (tl - ESP_WINDOW_SIZE + 1))
148 {
149 sa->seq_hi = th - 1;
150 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
151 }
152 else
153 {
154 sa->seq_hi = th;
155 if (seq <= tl)
156 return (sa->replay_window & (1ULL << diff)) ? 1 : 0;
157 else
158 return 0;
159 }
160 }
161
162 return 0;
163}
164
165/* TODO seq increment should be atomic to be accessed by multiple workers */
166always_inline void
167esp_replay_advance (ipsec_sa_t * sa, u32 seq)
168{
169 u32 pos;
170
171 if (seq > sa->last_seq)
172 {
173 pos = seq - sa->last_seq;
174 if (pos < ESP_WINDOW_SIZE)
175 sa->replay_window = ((sa->replay_window) << pos) | 1;
176 else
177 sa->replay_window = 1;
178 sa->last_seq = seq;
179 }
180 else
181 {
182 pos = sa->last_seq - seq;
183 sa->replay_window |= (1ULL << pos);
184 }
185}
186
187always_inline void
188esp_replay_advance_esn (ipsec_sa_t * sa, u32 seq)
189{
190 int wrap = sa->seq_hi - sa->last_seq_hi;
191 u32 pos;
192
193 if (wrap == 0 && seq > sa->last_seq)
194 {
195 pos = seq - sa->last_seq;
196 if (pos < ESP_WINDOW_SIZE)
197 sa->replay_window = ((sa->replay_window) << pos) | 1;
198 else
199 sa->replay_window = 1;
200 sa->last_seq = seq;
201 }
202 else if (wrap > 0)
203 {
204 pos = ~seq + sa->last_seq + 1;
205 if (pos < ESP_WINDOW_SIZE)
206 sa->replay_window = ((sa->replay_window) << pos) | 1;
207 else
208 sa->replay_window = 1;
209 sa->last_seq = seq;
210 sa->last_seq_hi = sa->seq_hi;
211 }
212 else if (wrap < 0)
213 {
214 pos = ~seq + sa->last_seq + 1;
215 sa->replay_window |= (1ULL << pos);
216 }
217 else
218 {
219 pos = sa->last_seq - seq;
220 sa->replay_window |= (1ULL << pos);
221 }
222}
223
224always_inline int
225esp_seq_advance (ipsec_sa_t * sa)
226{
227 if (PREDICT_TRUE (sa->use_esn))
228 {
229 if (PREDICT_FALSE (sa->seq == ESP_SEQ_MAX))
230 {
231 if (PREDICT_FALSE
232 (sa->use_anti_replay && sa->seq_hi == ESP_SEQ_MAX))
233 return 1;
234 sa->seq_hi++;
235 }
236 sa->seq++;
237 }
238 else
239 {
240 if (PREDICT_FALSE (sa->use_anti_replay && sa->seq == ESP_SEQ_MAX))
241 return 1;
242 sa->seq++;
243 }
244
245 return 0;
246}
247
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248always_inline void
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800249ipsec_proto_init ()
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250{
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800251 ipsec_proto_main_t *em = &ipsec_proto_main;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700252 vlib_thread_main_t *tm = vlib_get_thread_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253
254 memset (em, 0, sizeof (em[0]));
255
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800256 vec_validate (em->ipsec_proto_main_crypto_algs, IPSEC_CRYPTO_N_ALG - 1);
257 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_128].type =
258 EVP_aes_128_cbc ();
259 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_192].type =
260 EVP_aes_192_cbc ();
261 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_256].type =
262 EVP_aes_256_cbc ();
“mukeshyadav1984”72454dd2017-11-28 10:52:34 -0800263 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_128].iv_size = 16;
264 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_192].iv_size = 16;
265 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_256].iv_size = 16;
266 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_128].block_size =
267 16;
268 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_192].block_size =
269 16;
270 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_AES_CBC_256].block_size =
271 16;
272 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_DES_CBC].type =
273 EVP_des_cbc ();
274 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_3DES_CBC].type =
275 EVP_des_ede3_cbc ();
276 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_DES_CBC].block_size = 8;
277 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_3DES_CBC].block_size = 8;
278 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_DES_CBC].iv_size = 8;
279 em->ipsec_proto_main_crypto_algs[IPSEC_CRYPTO_ALG_3DES_CBC].iv_size = 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800281 vec_validate (em->ipsec_proto_main_integ_algs, IPSEC_INTEG_N_ALG - 1);
282 ipsec_proto_main_integ_alg_t *i;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800284 i = &em->ipsec_proto_main_integ_algs[IPSEC_INTEG_ALG_SHA1_96];
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700285 i->md = EVP_sha1 ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286 i->trunc_size = 12;
287
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800288 i = &em->ipsec_proto_main_integ_algs[IPSEC_INTEG_ALG_SHA_256_96];
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700289 i->md = EVP_sha256 ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 i->trunc_size = 12;
291
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800292 i = &em->ipsec_proto_main_integ_algs[IPSEC_INTEG_ALG_SHA_256_128];
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700293 i->md = EVP_sha256 ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294 i->trunc_size = 16;
295
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800296 i = &em->ipsec_proto_main_integ_algs[IPSEC_INTEG_ALG_SHA_384_192];
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700297 i->md = EVP_sha384 ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298 i->trunc_size = 24;
299
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800300 i = &em->ipsec_proto_main_integ_algs[IPSEC_INTEG_ALG_SHA_512_256];
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700301 i->md = EVP_sha512 ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302 i->trunc_size = 32;
303
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700304 vec_validate_aligned (em->per_thread_data, tm->n_vlib_mains - 1,
305 CLIB_CACHE_LINE_BYTES);
Matthew Smith29d85102016-05-01 14:52:08 -0500306 int thread_id;
307
308 for (thread_id = 0; thread_id < tm->n_vlib_mains - 1; thread_id++)
309 {
Marco Varlesef616d102017-11-09 15:16:20 +0100310#if OPENSSL_VERSION_NUMBER >= 0x10100000L
311 em->per_thread_data[thread_id].encrypt_ctx = EVP_CIPHER_CTX_new ();
312 em->per_thread_data[thread_id].decrypt_ctx = EVP_CIPHER_CTX_new ();
313 em->per_thread_data[thread_id].hmac_ctx = HMAC_CTX_new ();
314#else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700315 EVP_CIPHER_CTX_init (&(em->per_thread_data[thread_id].encrypt_ctx));
316 EVP_CIPHER_CTX_init (&(em->per_thread_data[thread_id].decrypt_ctx));
317 HMAC_CTX_init (&(em->per_thread_data[thread_id].hmac_ctx));
Marco Varlesef616d102017-11-09 15:16:20 +0100318#endif
Matthew Smith29d85102016-05-01 14:52:08 -0500319 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320}
321
322always_inline unsigned int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700323hmac_calc (ipsec_integ_alg_t alg,
324 u8 * key,
325 int key_len,
326 u8 * data, int data_len, u8 * signature, u8 use_esn, u32 seq_hi)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327{
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800328 ipsec_proto_main_t *em = &ipsec_proto_main;
Damjan Marion586afd72017-04-05 19:18:20 +0200329 u32 thread_index = vlib_get_thread_index ();
Marco Varlesef616d102017-11-09 15:16:20 +0100330#if OPENSSL_VERSION_NUMBER >= 0x10100000L
331 HMAC_CTX *ctx = em->per_thread_data[thread_index].hmac_ctx;
332#else
Damjan Marion586afd72017-04-05 19:18:20 +0200333 HMAC_CTX *ctx = &(em->per_thread_data[thread_index].hmac_ctx);
Marco Varlesef616d102017-11-09 15:16:20 +0100334#endif
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700335 const EVP_MD *md = NULL;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700336 unsigned int len;
337
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700338 ASSERT (alg < IPSEC_INTEG_N_ALG);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800340 if (PREDICT_FALSE (em->ipsec_proto_main_integ_algs[alg].md == 0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700341 return 0;
342
Damjan Marion586afd72017-04-05 19:18:20 +0200343 if (PREDICT_FALSE (alg != em->per_thread_data[thread_index].last_integ_alg))
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700344 {
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800345 md = em->ipsec_proto_main_integ_algs[alg].md;
Damjan Marion586afd72017-04-05 19:18:20 +0200346 em->per_thread_data[thread_index].last_integ_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700347 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700348
Marco Varlesef616d102017-11-09 15:16:20 +0100349 HMAC_Init_ex (ctx, key, key_len, md, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700351 HMAC_Update (ctx, data, data_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700353 if (PREDICT_TRUE (use_esn))
354 HMAC_Update (ctx, (u8 *) & seq_hi, sizeof (seq_hi));
355 HMAC_Final (ctx, signature, &len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356
“mukeshyadav1984”430ac932017-11-23 02:39:33 -0800357 return em->ipsec_proto_main_integ_algs[alg].trunc_size;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358}
359
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000360#endif /* __ESP_H__ */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700361
362/*
363 * fd.io coding-style-patch-verification: ON
364 *
365 * Local Variables:
366 * eval: (c-set-style "gnu")
367 * End:
368 */